🗓️ 07042026 1200

ZUSTAND CHEATSHEET

Quick reference for zustand API and common patterns.

Create a Store​

import { create } from 'zustand'

interface BearState {
bears: number
increase: () => void
reset: () => void
}

const useBearStore = create<BearState>((set) => ({
bears: 0,
increase: () => set((state) => ({ bears: state.bears + 1 })),
reset: () => set({ bears: 0 }),
}))

Use in Components​

// Subscribe to a slice (selective re-render)
const bears = useBearStore((state) => state.bears)

// Get an action (actions are stable, no re-render)
const increase = useBearStore((state) => state.increase)

// Multiple values — use shallow to avoid re-render on new object
import { useShallow } from 'zustand/react/shallow'

const { bears, increase } = useBearStore(
useShallow((state) => ({ bears: state.bears, increase: state.increase }))
)

Use Outside React​

// Get current state
const bears = useBearStore.getState().bears

// Subscribe to changes
const unsub = useBearStore.subscribe((state) => console.log(state.bears))

// Cleanup
unsub()

Async Actions​

const useStore = create<StoreState>((set) => ({
data: null,
loading: false,
fetch: async () => {
set({ loading: true })
const data = await fetchData()
set({ data, loading: false })
},
}))

Middleware​

persist — sync to storage​

import { persist } from 'zustand/middleware'

const useStore = create<StoreState>()(
persist(
(set) => ({ bears: 0 }),
{ name: 'bear-storage' } // localStorage key
)
)

devtools — Redux DevTools​

import { devtools } from 'zustand/middleware'

const useStore = create<StoreState>()(
devtools(
(set) => ({ bears: 0 }),
{ name: 'BearStore' }
)
)

immer — mutable-style updates​

import { immer } from 'zustand/middleware/immer'

const useStore = create<StoreState>()(
immer((set) => ({
nested: { deep: { value: 0 } },
update: () => set((state) => { state.nested.deep.value += 1 }),
}))
)

Combining middleware​

const useStore = create<StoreState>()(
devtools(
persist(
immer((set) => ({ /* ... */ })),
{ name: 'storage-key' }
),
{ name: 'StoreName' }
)
)

Store Slices​

interface BearSlice { bears: number; addBear: () => void }
interface FishSlice { fishes: number; addFish: () => void }

const createBearSlice: StateCreator<BearSlice & FishSlice, [], [], BearSlice> = (set) => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
})

const createFishSlice: StateCreator<BearSlice & FishSlice, [], [], FishSlice> = (set) => ({
fishes: 0,
addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})

const useStore = create<BearSlice & FishSlice>()((...a) => ({
...createBearSlice(...a),
...createFishSlice(...a),
}))

Common Gotchas​

ProblemFix
Re-renders on every state changeUse a selector: useStore(s => s.field)
Object selector causes infinite re-renderUse useShallow or separate selectors
Stale state in async callbackUse get(): create((set, get) => ...)
Middleware TypeScript errorsAdd () after create<Type>() before middleware

References​