Organize a large store by domain
A growing application has unrelated domains such as bears, fish, authentication, and UI state.
Zustand · Const
The slices pattern composes several focused Zustand state creators into one bounded store. It improves modularity while preserving a single store API.
Store composition divides a large Zustand store into smaller slice creators, then spreads those slices into one bounded store. Each slice receives the shared store arguments, so its actions can update the combined state and interact with other slices when needed.
create((...a) => ({ ...createSliceA(...a), ...createSliceB(...a) }))create function.import { create } from 'zustand'
type BearSlice = {
bears: number
addBear: () => void
}
type FishSlice = {
fish: 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 => ({
fish: 0,
addFish: () => set((state) => ({ fish: state.fish + 1 })),
})
export const useBoundStore = create<Store>()((...a) => ({
...createBearSlice(a[0]),
...createFishSlice(a[0]),
}))Creates one Zustand store by spreading independently defined bear and fish slices.
A growing application has unrelated domains such as bears, fish, authentication, and UI state.
A feature needs one operation that coordinates updates across multiple state areas.
A team wants to add persistence or another middleware to a modular store.
The slices pattern keeps related state and actions in separate creator functions, then combines their returned objects into one store. Consumers use the resulting bounded store as a single Zustand store.
Follow-up: How would a slice call an action from another slice? Use the shared store API, typically get(), inside the slice action to invoke the other slice's action.
A combined store is created by spreading each slice creator's result into the object passed to create. The resulting store exposes all slice state and actions through one store API.
Follow-up: How can middleware be applied safely? Wrap the combined store creator, not the individual slice creators.
Slices can define cross-slice actions because their creators receive the shared store arguments. An action can call get().addBear() and get().addFish() within one function.
Follow-up: What architectural rule should be followed for middleware? Apply middleware only at the combined-store level.
Slices Patterncombinepersistcreatesetget