Zustand — Guia Completo
Store simples, seletores, middleware (persist, devtools, immer), e padrões avançados.
Definição
Zustand é uma lib minimalista de estado global (1kb). Store é criado com create(), actions ficam no mesmo objeto que o estado, seletores evitam re-renders desnecessários. Middleware: persist (localStorage automático), devtools (Redux DevTools), immer (mutação sintática). Sem Provider, sem boilerplate, sem Context.
Problema → Solução
Problema
Redux para uma funcionalidade simples exige: types, actions, reducers, selectors, thunks — 100 linhas para guardar um boolean. Context API com re-render de todos os consumers.Solução
Zustand: create() com estado e actions inline. Seletor para consumir só o que precisa (previne re-render). persist middleware para persistir no localStorage com uma linha. devtools para debugging com Redux DevTools.Dica de entrevista
Tip
Seletores são críticos: `useStore(s => s.count)` re-renderiza só quando count muda. `useStore()` sem seletor re-renderiza quando qualquer parte do store muda. Sempre use seletor granular.Código
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
interface CartStore {
items: CartItem[]
addItem: (item: CartItem) => void
removeItem: (id: string) => void
total: number
}
export const useCartStore = create<CartStore>()(
devtools(
persist(
immer((set, get) => ({
items: [],
addItem: (item) => set(state => {
state.items.push(item) // Immer: mutação segura
}),
removeItem: (id) => set(state => {
state.items = state.items.filter(i => i.id !== id)
}),
get total() {
return get().items.reduce((s, i) => s + i.price, 0)
},
})),
{ name: 'cart-storage' } // persist config
),
{ name: 'CartStore' } // devtools name
)
)
// Consumir com seletor granular
function CartBadge() {
// ✅ só re-renderiza quando items.length muda
const count = useCartStore(s => s.items.length)
return <span>{count}</span>
}
function AddButton({ item }) {
// ✅ actions são estáveis (referência não muda)
const addItem = useCartStore(s => s.addItem)
return <button onClick={() => addItem(item)}>Adicionar</button>
}Perguntas de entrevista
Q.Como dividir uma store Zustand grande?▾
A.Slice pattern: criar múltiplas slices e combinar: `create<State>()((...args) => ({ ...createAuthSlice(...args), ...createCartSlice(...args) }))`. Ou criar stores separadas por domínio — Zustand não tem store única obrigatória, ao contrário do Redux.
Q.Como persistir estado com Zustand?▾
A.Middleware persist: `create(persist((set) => ({ count: 0, inc: () => set(s => ({count: s.count+1})) }), { name: "counter-storage" }))`. Persiste no localStorage por padrão. Customizar storage (sessionStorage, IndexedDB), partializar quais campos persistir, e migrar state entre versões.
Q.Zustand funciona com Server Components?▾
A.Não diretamente — Zustand é client-side (usa window/browser APIs). Inicializar store com dados do servidor via prop do Client Component ou via useHydrateAtoms (Jotai). No Next.js App Router: criar uma instância por request no servidor usando a forma funcional do create.
Termos relacionados
70/122← →