Create a To-Do component

For our To-Do application to work, we need to create a To-Do component that contains the information associated with a To-Do.

Create a new file src/js/components/Todo.jsx.

The first thing we need to do is to create a new state of our To-Do. Allotize uses a URI scheme to be able to identify different resources. We will discover our To-Do's via todo/:todoId and use a unique id for every entry. To do so, we use the hook called useAllotizeState available in the allotize-react package. In this case, we want to create a new route to point to the state of our To-Do. Telling Allotize that this is our intention, we simply set route to match our access pattern and state to some initial state.

import { useAllotizeState } from "allotize-react";

export function Todo(props) {
    const [state, setState] = useAllotizeState({
        route: `todo/${props.todoId}`,
        state: {
            description: props.desc,
            done: false,
        },
    });

    return (
      <div>
      </div>
    );
}

Now we can use state and setState just like we use the regular useState-hook. In our case, we want a button that can mark the state.done as true/false.

import React, { useEffect, useRef, useState } from "react";
import { useAllotizeState } from "allotize-react";

export function Todo(props) {
    const [state, setState] = useAllotizeState({
        route: `todo/${props.todoId}`,
        state: {
            description: props.desc,
            done: false,
        },
    });

    return (
      <div>
        [TODO-{props.todoId}]
        <button onClick={() => setState({...state, done: !state.done})}>
            { state.done ? "Restore" : "Done"}
        </button>
      </div>
    );
}

Finally, we add some extra styling and buttons to our To-Do. This part can be skipped if you don't want to style your components using bootstrap.

import React, { useEffect, useRef, useState } from "react";
import { useAllotizeState } from "allotize-react";

const todoStyle = {
    padding: "12px",
}

const doneStyle = {
    opacity: 0.4,
}

export function Todo(props) {
    const [state, setState] = useAllotizeState({
        route: `todo/${props.todoId}`,
        state: {
            description: props.desc,
            done: false,
        },
    });

    const [edit, setEdit] = useState(false);
    const editInput = useRef();
    useEffect(() => {editInput.current && editInput.current.focus();});

    return (
      <div style={state.done ? {...todoStyle, ...doneStyle} : todoStyle}>
        <div className="card">
        <div className="card-header">
            <strong className="mr-auto">
                {state.done ? "Done - " : ""}[TODO-{props.todoId}]
            </strong>
            <div className="btn-group btn-group-sm float-right" role="group" aria-label="Basic example">
                <button className="btn btn-primary" onClick={() => setState({...state, done: !state.done})}>
                    { state.done ? "Restore" : "Done"}
                </button>
                <button className="btn btn-secondary" onClick={() => setEdit(true)}>Edit</button>
                <button className="btn btn-danger" onClick={() => props.deleteTodo(props.todoId)}>
                    Delete
                </button>
            </div>
        </div>
        <div className="card-body">
            {
                edit ?
                <form className="input-group mb-3" onSubmit={() => setEdit(false)}>
                    <input
                    ref={editInput}
                    type="text"
                    className="form-control"
                    name="description"
                    onChange={(e) => setState({...state, description: e.target.value})}
                    placeholder="To-Do description"
                    value={state.description}
                    aria-describedby="button-addon2"/>
                    <div className="input-group-append">
                    <button className="btn btn-primary" type="submit" id="button-addon2">
                        Save
                    </button>
                    </div>
                </form>
                :
                state.description
            }
        </div>
        </div>

      </div>
    );
}