Lesson 16 / 25

Creating a Store

State and actions together.

create returns a hook

create from zustand takes a function (set, get) => ({ ...state, ...actions }) and returns a React hook. Components call the hook with a selector to read state. set merges a partial object into state (a shallow merge at the top level), or takes an updater function set((state) => partial). get reads current state inside actions. No Provider is required because the store lives in module scope. In TypeScript, write create<State>()(...) with the extra parentheses so middleware types infer correctly.

A store is just a hook

Zustand creates small stores as hooks with no Provider and very little ceremony.

Three ideas: creating stores, selectors and re-renders, async actions and slices.
Figure 6.1 — Components subscribing to slices of a Zustand store.

A counter and cart store

store.ts and a component.

import { create } from 'zustand';

type CartState = {
  items: { id: string; qty: number }[];
  add: (id: string) => void;
  clear: () => void;
};

export const useCart = create<CartState>()((set) => ({
  items: [],
  add: (id) =>
    set((state) => {
      const hit = state.items.find((i) => i.id === id);
      return {
        items: hit
          ? state.items.map((i) => (i.id === id ? { ...i, qty: i.qty + 1 } : i))
          : [...state.items, { id, qty: 1 }],
      };
    }),
  clear: () => set({ items: [] }),
}));

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

A shared whiteboard

Anyone in the office can glance at one corner of the whiteboard (a selector) or write on it with the agreed marker (an action). No reception desk (Provider) is needed to get in.

Quick check: What does set({ items: [] }) do in Zustand?

  • Deep-merges every nested object
  • Replaces the whole state with { items: [] }
  • Shallow-merges items into the existing state
  • Throws because set needs a function
Answer

Shallow-merges items into the existing state — set merges at the top level unless you pass replace = true.