Skip to content

Zustand State Management

Zustand is a small, fast state management library using hooks. No providers required — create a store and call it from any component. Popular for global UI state, carts, and preferences without Redux ceremony.

Creating a Zustand Store

create((set, get) => ({ ... })) defines state and actions. Components subscribe with useStore(selector) and re-render only when selected slice changes.

Zustand works outside React too — call store.getState() in utilities. Middleware adds persistence, devtools, and immer.

import { create } from 'zustand';

const useCartStore = create((set) => ({
  items: [],
  addItem: (item) => set((s) => ({ items: [...s.items, item] })),
  clear: () => set({ items: [] }),
}));

function CartBadge() {
  const count = useCartStore((s) => s.items.length);
  return <span>{count}</span>;
}

Selector (s) => s.items.length limits re-renders to count changes only.

Zustand Store Pattern

const useStore = create((set, get) => ({
  bears: 0,
  increase: () => set({ bears: get().bears + 1 }),
}));
  • No Provider wrapper needed.
  • Use selectors to subscribe to slices.
  • Actions live alongside state in the store.
  • persist middleware saves to localStorage.

Zustand Quick Reference

Common Zustand APIs and patterns.

API Usage
create Define store
set Update state
get Read current state in actions
Selector hook useStore(s => s.field)
persist localStorage/sessionStorage
devtools Redux DevTools integration

Splitting Large Stores

Combine slice pattern or multiple stores by domain — useAuthStore, useCartStore — instead of one enormous store object.

Persistence Middleware

Wrap store with persist to survive page reloads for carts, drafts, and user preferences.

const useSettingsStore = create(
  persist(
    (set) => ({ theme: 'light', setTheme: (t) => set({ theme: t }) }),
    { name: 'settings-storage' }
  )
);

Common Mistakes

  • Selecting entire store object causing broad re-renders.
  • Duplicating server cache data in Zustand.
  • One giant store instead of domain splits.
  • Mutating state directly without set/immer.

Key Takeaways

  • Zustand offers minimal global state with hook subscriptions.
  • Selectors prevent unnecessary re-renders.
  • No provider required; works inside and outside React.
  • Great middle ground between context and Redux.

Pro Tip

Use shallow compare selector from zustand/shallow when selecting multiple fields: useStore(s => ({ a: s.a, b: s.b }), shallow).