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>
);
}