Todo App (Store API)
This is a basic todo app with browser backed storage using only rvx's store API.
Note, that this example doesn't include any storage error handling or validation.
import { For, Show, Signal, effect, sig } from "rvx";
import { reflect, wrap } from "rvx/store";
const STORAGE_KEY = "rvx-examples:todo-app";
export function Example() {
const name = sig("");
// Load items from storage by creating a
// deep reactive wrapper for the items array:
let items: Item[];
try {
items = wrap(JSON.parse(localStorage.getItem(STORAGE_KEY)!) ?? []);
} catch (error) {
items = wrap([]);
console.error(error);
}
function add() {
if (name.value) {
// Since "items" is a reactive wrapper, it can be modified directly:
items.push({ name: name.value, done: false });
name.value = "";
}
}
effect(() => {
try {
// "JSON.stringify" accesses all reactive properties of
// "items" and will re-run this effect when anything changes:
localStorage.setItem(STORAGE_KEY, JSON.stringify(items));
} catch (error) {
console.error(error);
}
});
return <div class="column">
<div class="row">
<TextInput value={name} action={add} />
<button on:click={add}>Add</button>
</div>
<ul>
<For each={items}>
{item => <li class="row">
<TextInput value={reflect(item, "name")} />
<Show
when={() => item.done}
else={() => <>
<button on:click={() => { item.done = true }}>Done</button>
</>}
>
{() => <>
<button on:click={() => { item.done = false }}>Undone</button>
<button on:click={() => {
items.splice(items.indexOf(item), 1);
}}>Remove</button>
</>}
</Show>
</li>}
</For>
</ul>
</div>;
}
function TextInput(props: {
value: Signal<string>;
action?: () => void;
}) {
return <input
type="text"
prop:value={props.value}
on:input={event => {
props.value.value = (event.target as HTMLInputElement).value;
}}
on:keydown={event => {
if (event.key === "Enter" && props.action) {
event.preventDefault();
props.action();
}
}}
/>;
}
interface Item {
name: string;
done: boolean;
}