Deeply nested updates
Updating objects or records several levels below the store root.
Zustand · Const
The immer middleware enables convenient immutable updates in Zustand. Wrap a state creator with it to write draft mutations inside set callbacks.
The immer middleware adapts a Zustand state creator so updater callbacks receive Immer drafts. This permits direct-looking mutations such as state.count += qty; Immer converts them into immutable updates before Zustand publishes the result.
immer<T>(stateCreatorFn: StateCreator<T, [], []>): StateCreator<T, [['zustand/immer', never]], []>| Name | Type | Description |
|---|---|---|
stateCreatorFn | StateCreator<T, [], []> | A Zustand state creator receiving set, get, and store, usually returning the state and actions to expose. |
A state creator function: StateCreator<T, [['zustand/immer', never]], []>
set, get, and store arguments.import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
type Store = {
count: number
increment: () => void
}
const useStore = create<Store>()(
immer((set) => ({
count: 0,
increment: () =>
set((state) => {
state.count += 1
}),
})),
)
useStore.getState().increment()
console.log(useStore.getState().count)Wrap the state creator with immer, then mutate the draft inside a set callback while Immer produces the immutable next state.
Updating objects or records several levels below the store root.
Writing counters and other action logic without manually spreading state layers.
Keeping Zustand's immutable state model while using mutable-looking draft code.
immer middleware do?immer takes a Zustand state creator and returns another state creator with Immer-aware updates. The wrapped creator can use set((state) => { state.count += qty }), and Immer turns that draft mutation into an immutable state transition.
Follow-up: What does the middleware return? It returns a state creator function, with the Zustand Immer mutator type applied.
immer?The middleware signature is immer<T>(stateCreatorFn: StateCreator<T, [], []>): StateCreator<T, [['zustand/immer', never]], []>. Its input creator receives set, get, and store, and normally returns the store's exposed state and actions.
Follow-up: Why can an updater mutate state safely? The callback operates on an Immer draft, while the resulting store state remains immutable.
Immer must be installed as a direct dependency, and updates must follow Immer's rules. In particular, class objects require [immerable] = true; otherwise Zustand may see unchanged references and skip subscriptions.
Follow-up: What symptom can incorrect class handling cause? The current and next state can compare equal, so subscribers may not be called.
setgetstoreStateCreatorzustand/middleware/immerImmer