Zustand Examples

Explore these practical examples to learn how to use Zustand in real-world applications.

Simple Counter

A basic counter example demonstrating state updates and actions.

import { create } from 'zustand'

const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}))

function Counter() {
  const { count, increment, decrement, reset } = useCounterStore()
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

Shopping Cart

A shopping cart with add, remove, and quantity management.

import { create } from 'zustand'

interface CartItem {
  id: string
  name: string
  price: number
  quantity: number
}

const useCartStore = create((set) => ({
  items: [] as CartItem[],
  addItem: (item: Omit<CartItem, 'quantity'>) =>
    set((state) => {
      const existing = state.items.find((i) => i.id === item.id)
      if (existing) {
        return {
          items: state.items.map((i) =>
            i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
          ),
        }
      }
      return { items: [...state.items, { ...item, quantity: 1 }] }
    }),
  removeItem: (id: string) =>
    set((state) => ({
      items: state.items.filter((item) => item.id !== id),
    })),
  updateQuantity: (id: string, quantity: number) =>
    set((state) => ({
      items: state.items.map((item) =>
        item.id === id ? { ...item, quantity } : item
      ),
    })),
  clearCart: () => set({ items: [] }),
  total: () => {
    const state = useCartStore.getState()
    return state.items.reduce(
      (sum, item) => sum + item.price * item.quantity,
      0
    )
  },
}))

Form Management

Managing form state with validation and submission.

import { create } from 'zustand'

interface FormState {
  values: Record<string, any>
  errors: Record<string, string>
  isSubmitting: boolean
}

const useFormStore = create<FormState & {
  setField: (name: string, value: any) => void
  setError: (name: string, error: string) => void
  reset: () => void
  submit: () => Promise<void>
}>((set, get) => ({
  values: {},
  errors: {},
  isSubmitting: false,
  setField: (name, value) =>
    set((state) => ({
      values: { ...state.values, [name]: value },
      errors: { ...state.errors, [name]: '' },
    })),
  setError: (name, error) =>
    set((state) => ({
      errors: { ...state.errors, [name]: error },
    })),
  reset: () =>
    set({ values: {}, errors: {}, isSubmitting: false }),
  submit: async () => {
    set({ isSubmitting: true })
    try {
      const { values } = get()
      // Submit form data
      await fetch('/api/submit', {
        method: 'POST',
        body: JSON.stringify(values),
      })
      set({ isSubmitting: false })
    } catch (error) {
      set({ isSubmitting: false })
    }
  },
}))

Async Data Fetching

Handling API calls with loading and error states.

import { create } from 'zustand'

interface User {
  id: number
  name: string
  email: string
}

interface UserStore {
  users: User[]
  loading: boolean
  error: string | null
  fetchUsers: () => Promise<void>
}

const useUserStore = create<UserStore>((set) => ({
  users: [],
  loading: false,
  error: null,
  fetchUsers: async () => {
    set({ loading: true, error: null })
    try {
      const response = await fetch('https://api.example.com/users')
      if (!response.ok) throw new Error('Failed to fetch')
      const users = await response.json()
      set({ users, loading: false })
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : 'Unknown error',
        loading: false,
      })
    }
  },
}))

function UserList() {
  const { users, loading, error, fetchUsers } = useUserStore()

  useEffect(() => {
    fetchUsers()
  }, [])

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error}</div>

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  )
}