[]previous and next page

useStore

The state hook.

The state hook. Pass a single value for a reactive cell, or plain data for a deep store:

ts
const [count, setCount] = useStore(0);                 // count() / setCount(n => n + 1)
const [todos, setTodos] = useStore({ items: [] as Todo[] });
todos.items[0]?.done;                                  // tracks exactly this property
setTodos((draft) => { draft.items.push(todo); });      // notifies only what changed
setTodos("items", (t) => t.id === 3, "done", true);    // path form

Reads inside effects, memos and JSX subscribe to the exact value or property read; writes notify exactly the readers of what changed, in one batch. A store wraps plain objects and arrays in place; class instances, Date, Map, Set and functions are single values. A value that may be null or another type (Todo[] | null) is a single value too: it is replaced as a whole, and plain data assigned to it is read through the same fine-grained proxies a store uses.

Import#

ts
import { useStore } from "@shadow-js/core";

Signature#

ts
function useStore<T extends NotMixed<T>>(initial: T, options?: StoreOptions): StoreResult<T>

function useStore<T>(initial: MixedInitial<T>, options?: StoreOptions): StoreResult<T>

Parameters#

Name Description
initial Initial value or plain data. Plain objects and arrays are wrapped in place, not copied.
options name labels the store in messages. Undefined uses the default (unnamed).

Returns#

[read, write] for a single value, [store, setStore] for plain data.

Throws#

  • ShadowError WRITE_IN_MEMO from the setter, in development builds only, when it is called while a useMemo computation runs. setStore throws TypeError (production messages SHADOW_STORE_*) for an update it cannot apply: no argument, a bad path step, a path through a value that is not an object, a reserved key such as __proto__, or a non-array value for an array store. Writing to the store view itself throws TypeError (SHADOW_STORE_READ_ONLY).

Examples#

ts
import { useStore } from "@shadow-js/core";

interface Todo { id: number; title: string; done: boolean }

const [count, setCount] = useStore(0);
const [todos, setTodos] = useStore({ items: [] as Todo[] });
setCount((n) => n + 1);
setTodos((draft) => {
  draft.items.push({ id: 1, title: "Write docs", done: false });
});
setTodos("items", (todo) => todo.id === 1, "done", true);
console.log(count(), todos.items[0]?.done); // 1 true