use Graft Store
A value that is held, with a way back to the one it started with.
API
Options
| prop | type | default | |
|---|---|---|---|
defaultValue | T | — | the starting value, and the one reset goes back to |
Returns
| prop | type | default | |
|---|---|---|---|
value? | T | — | the current value |
setValue? | Dispatch<SetStateAction<T>> | — | as useState, updater included |
resetValue? | () => void | — | back to the value it started with |
id? | string | — | stable id |
Usage
A value and a way back
// -constants/graft_draft.ts
export const GraftDraft = createGraft({ name: "GraftDraft", graft: useGraftStore<string | null> });
// -components/draft_controls.tsx
export const DraftControls = () => {
const { resetValue, setValue, value } = GraftDraft.use();
return (
<>
<Chip>{value ?? "null"}</Chip>
<Button onClick={() => setValue("edited")}>set</Button>
<Button onClick={() => setValue(null)}>empty</Button>
<Button onClick={resetValue}>reset</Button>
</>
);
};Details
useState, distributed
The value is useState and nothing else — same semantics, setValue takes an updater, batching and transitions behave as you expect. The hook adds the one exit worth having: resetValue, back to the value it started with.
Whether the store can be empty is your decision, not the hook's: a useGraftStore<Draft> always holds a draft, a useGraftStore<Draft | null> can be emptied with setValue(null). Nothing is nullable behind your back, so value is the type you asked for and needs no ?? at every read.
The default is read once
defaultValue is required and read on mount, then kept: resetting twice gives the same thing twice, even if what you passed has since changed. It takes a value, not a factory — if the default has to be computed, compute it before and hand over the result.
It also means a store can be seeded from something above it: a provider mounted when a dialog opens starts from the payload that dialog carries, and unmounting is how it is cleared. No effect to synchronise, and no stale value to reset by hand.
function useGraft() {
const dialog = GraftDialogInvoice.use();
return useGraftStore<Invoice | null>({ defaultValue: dialog.storage });
}