Zustand: A Store is Just a Hook
1.2KB, no providers, no boilerplate.
import { create } from 'zustand'
export const useCartStore = create((set) => ({
items: [],
total: 0,
addItem: (product, qty) => set((state) => {
const existing = state.items.find(i => i.id === product.id)
const items = existing
? state.items.map(i => i.id === product.id ? { ...i, qty: i.qty + qty } : i)
: [...state.items, { ...product, qty }]
return { items, total: items.reduce((s, i) => s + i.price * i.qty, 0) }
}),
clearCart: () => set({ items: [], total: 0 }),
}))
Granular Selectors
const count = useCartStore(state => state.items.length) // Re-renders only when count changes
const { clearCart } = useCartStore() // Stable reference
Immer + Persistence
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
import { persist } from 'zustand/middleware'
const useStore = create(persist(immer((set) => ({
todos: [],
addTodo: (text) => set(state => { state.todos.push({ id: Date.now(), text, done: false }) }),
})), { name: 'app-state' }))
Slices Pattern
const createAuth = (set) => ({
user: null,
login: async (creds) => { const user = await auth(creds); set({ user }) },
logout: () => set({ user: null }),
})
export const useStore = create((...args) => ({ ...createAuth(...args) }))
-> Debug store state with the JSON Viewer.