Separate domain state
A store has independent domains such as bears and fish but should remain one global store.
Zustand · Const
Zustand's slices pattern splits a large store into modular state-and-action creators, then combines them into one bounded store. Slice actions can coordinate through get(), while middleware belongs on the combined store.
Store slicing divides a large Zustand store into focused slice creators. Each creator receives the store's arguments such as set and get, returns its own state and actions, and the final store combines those returned objects into one bounded store; cross-slice actions can call methods through get().
create((...args) => ({ ...createSliceA(...args), ...createSliceB(...args) }))| Name | Type | Description |
|---|---|---|
set | function | Store updater supplied by Zustand; slice actions use it to apply partial or functional updates. |
get | function | Store accessor supplied by Zustand; useful for reading combined state and invoking other slice actions. |
A single bounded Zustand store containing the properties and actions returned by all combined slices.
import { create } from 'zustand'
type BearSlice = {
bears: number
addBear: () => void
}
type FishSlice = {
fishes: number
addFish: () => void
}
type Store = BearSlice & FishSlice
const createBearSlice = (set: (fn: (s: Store) => Partial<Store>) => void): BearSlice => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
})
const createFishSlice = (set: (fn: (s: Store) => Partial<Store>) => void): FishSlice => ({
fishes: 0,
addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})
export const useBoundStore = create<Store>()((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}))Each slice defines part of the state and actions, then the combined store spreads those slice creators into one Zustand store.
A store has independent domains such as bears and fish but should remain one global store.
Several actions must coordinate changes across multiple state domains.
A growing application needs state modules that can be developed and tested independently.
A slice is a function that receives the store arguments and returns part of the store's state and actions. The application combines those partial objects with object spread when creating one bounded store.
Follow-up: How would a slice coordinate with another slice? Use the get argument and invoke another slice's action, then include the coordinating slice in the combined store.
Slices improve modularity by separating a large store into smaller, composable pieces. They do not create separate runtime stores when combined; the resulting application uses one store containing all slice properties.
Follow-up: Why can a cross-slice action access another slice? Because every slice creator is initialized with the same store API, so get() can read the combined state and actions.
The combined store is created by spreading each slice creator's result into the object returned to create. In TypeScript, the overall store type can be expressed as an intersection of the slice types.
Follow-up: Where should devtools or other middleware be placed? Wrap the combined creator, and account for the middleware mutators in the slice creator types when using TypeScript.
setgetcreateStateCreatorcombinedevtools