Reactions & Watch
Derive state from state, and run side-effects outside React.
Reactions — build state from other state
Section titled “Reactions — build state from other state”A reaction watches one slice of state and, when it changes, runs a function (inside Immer) to update other fields on the same store. Reactions run before any subscribers are notified, so these derived fields are always up to date within a single render.
interface IState { count: number; doubled: number; // derived — never written by hand history: number[]; // derived}
const store = new Store<IState>({ count: 0, doubled: 0, history: [] });
store.createReaction( (s) => s.count, // watch (count, draft) => { // derive draft.doubled = count * 2; draft.history = [...draft.history, count].slice(-12); }, { runNow: true }, // run once immediately to seed derived state);createReaction returns a disposer to remove the reaction.
Watch — side-effects outside React
Section titled “Watch — side-effects outside React”watch follows a slice of state and runs your callback only when that slice actually changes. Great for logging, saving to storage, or keeping non-React code in sync.
const unsubscribe = store.watch( (s) => s.count, (count, allState, previousCount) => { console.log(`count: ${previousCount} → ${count}`); },);The low-level store.subscribe(() => { ... }) runs on every update (no slice, no arguments) — it’s the basic building block the React adapter is built on.
Reaction vs watch vs subscribe
Section titled “Reaction vs watch vs subscribe”| API | Runs when | Use it for |
|---|---|---|
createReaction | a watched slice changes | building more state onto the same store |
watch | a watched slice actually changes | side-effects (logging, saving, syncing) |
subscribe | every update | the low-level building block; for writing adapters |