Skip to content

Patches & Devtools

Immer patch streams for undo/redo and sync, plus the state inspector panel.

Every update can produce Immer patches — a small description of exactly what changed. Patches power undo/redo, syncing, and the devtools. They’re only built when something is actually listening for them, so you pay nothing for them the rest of the time.

import { applyPatchesToStore } from "@nice-code/state";
// Listen to patches for every update
const stop = store.listenToPatches((patches, inversePatches) => {
sendToServer(patches);
});
// Or collect patches for a single update
store.update((s) => { s.count += 1; }, (patches, inverse) => {
undoStack.push(inverse);
});
// Apply patches (received from elsewhere, or to undo)
store.applyPatches(patches);

Inverse patches are how undo works: keep a stack of them, and applyPatches the top one to undo the last change.

An inspector for your stores that needs no setup — a timeline of changes, before/after diffs, a live view of your state you can edit directly, and one-click undo using patches. Name the stores you want to observe; nothing renders inside your app.

devtools.ts
import { createNiceDevtools } from "@nice-code/devtools";
import { counterStore } from "./counterStore";
export const devtools = createNiceDevtools({
topologyId: "my-app",
stores: { counterStore }, // the key is the label the panel shows
});

Underneath that is a StateDevtoolsCore (registerStore("counterStore", counterStore)) streamed through stateBridgeScope, both from @nice-code/state/devtools/browser. A store created later joins with devtools.registerStore(…).

The panel — rendered in the devtools window — lets you filter by store, inspect and edit live state, view per-change diffs and patches, pause the timeline, and revert a change via its inverse patches.

Registering a store attaches a patch listener (a negligible dev-time cost). Keep devtools setup out of production bundles.

EntryContents
@nice-code/stateStore, update, applyPatchesToStore, core types
@nice-code/state/reactuseStoreState, useLocalStore, InjectStoreState
@nice-code/state/devtools/browserStateDevtoolsCore, NiceStateDevtools