Skip to content

Reactions & Watch

Derive state from state, and run side-effects outside React.

A reaction watches a slice and, when it changes, runs a recipe inside Immer to derive further state on the same store. Reactions run before subscribers are notified, so derived fields are always consistent in 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 subscribes to a derived slice and fires only when it changes structurally. Ideal for logging, persistence, or syncing to non-React code.

const unsubscribe = store.watch(
(s) => s.count,
(count, allState, previousCount) => {
console.log(`count: ${previousCount}${count}`);
},
);

The low-level store.subscribe(() => { ... }) fires on every committed update (no slice, no args) — the primitive the React adapter builds on.

APIFires whenUse for
createReactiona watched slice changesderiving more state onto the same store
watcha watched slice changes structurallyside-effects (logging, persistence, sync)
subscribeevery committed updatelow-level primitive; building adapters

Next: Patches & devtools →