intermediate
Store slices
Split larger stores into cohesive slices while keeping action ownership and cross-slice dependencies clear.
Large Zustand stores split into slices — factory functions that receive `set`, `get`, and merge into one `create` state. Each slice owns actions and state fields for a feature.
import { create } from 'zustand';
const createBearSlice = (set) => ({
bears: 0,
addBear: () => set((s) => ({ bears: s.bears + 1 })),
});
const createFishSlice = (set) => ({
fish: 0,
addFish: () => set((s) => ({ fish: s.fish + 1 })),
});
const useStore = create((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}));
Cross-slice reads use `get()` inside actions. Avoid circular dependencies between slices; extract shared helpers when needed.
The trade-off is modular stores versus coordination cost when slices share derived or persisted fields.
On interviews: slice boundaries versus multiple separate stores.
Common pitfalls: slices mutating each other's shape informally, name collisions on merge, and god-slice anti-pattern.
Checklist:
- One create with composed slices.
- Clear action ownership per slice.
- get() for cross-slice coordination.
- Split stores only when lifecycles differ.