zustand
Zustand 5+ state management. Use when creating stores, selectors, middleware, or persisting state.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Zustand 5+
Create store — named import
import { create } from 'zustand'
const useStore = create<State>()((set, get) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
reset: () => set({ count: 0 })
}))
// NOT default import — that's v4
Selectors with useShallow
import { useShallow } from 'zustand/shallow'
// Single value — no useShallow needed
const count = useStore((s) => s.count)
// Multiple values — use useShallow to prevent re-renders
const { name, email } = useStore(
useShallow((s) => ({ name: s.name, email: s.email }))
)
// NOT custom equality in create() — that's v4
Custom equality (if needed)
import { createWithEqualityFn } from 'zustand/traditional'
import { shallow } from 'zustand/shallow'
const useStore = createWithEqualityFn<State>()(
(set) => ({ ... }),
shallow
)
// NOT create(fn, shallow) — that's v4
Persist middleware
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
const useStore = create<State>()(
persist(
(set) => ({
theme: 'dark',
setTheme: (t) => set({ theme: t })
}),
{ name: 'app-storage' }
)
)
// v5: Initial state NOT auto-persisted on creation
// Hydration happens async — handle loading state
Persist with partialize
persist(
(set) => ({ ... }),
{
name: 'app-storage',
partialize: (state) => ({ theme: state.theme }) // only persist theme
}
)
setState with replace
// Partial update (default)
set({ count: 5 })
// Full replace — must provide complete state
set({ count: 5, name: 'New', items: [] }, true)
// v5: replace=true requires ALL fields
Combine middleware
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
const useStore = create<State>()(
devtools(
persist(
(set) => ({ ... }),
{ name: 'storage' }
),
{ name: 'MyStore' }
)
)
Access outside React
// Get current state
const count = useStore.getState().count
// Subscribe to changes
const unsub = useStore.subscribe((state) => console.log(state))
// Set state directly
useStore.setState({ count: 10 })
Slices pattern
const createUserSlice = (set) => ({
user: null,
setUser: (user) => set({ user })
})
const createCartSlice = (set) => ({
items: [],
addItem: (item) => set((s) => ({ items: [...s.items, item] }))
})
const useStore = create((...a) => ({
...createUserSlice(...a),
...createCartSlice(...a)
}))
Avoid
- Default import → named
import { create } -
create(fn, shallow)→createWithEqualityFnfromzustand/traditional - Object selector without
useShallow→ causes re-renders -
setState({}, true)→ replace requires complete state - Assuming persist hydrates sync → handle loading state
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-03-03
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!