DEV Community

Alex Spinov
Alex Spinov

Posted on

Zustand Has a Free API You're Not Using

Zustand is the simplest React state manager — just a hook. But most developers miss the powerful middleware and patterns that make it a full Redux replacement.

The Free APIs You're Missing

1. Slices Pattern — Modular Store

import { create, StateCreator } from "zustand";

interface AuthSlice {
  user: User | null;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

interface CartSlice {
  items: CartItem[];
  addItem: (item: CartItem) => void;
  total: () => number;
}

const createAuthSlice: StateCreator<AuthSlice & CartSlice, [], [], AuthSlice> = (set) => ({
  user: null,
  login: async (email, password) => {
    const user = await api.login(email, password);
    set({ user });
  },
  logout: () => set({ user: null }),
});

const createCartSlice: StateCreator<AuthSlice & CartSlice, [], [], CartSlice> = (set, get) => ({
  items: [],
  addItem: (item) => set((s) => ({ items: [...s.items, item] })),
  total: () => get().items.reduce((sum, i) => sum + i.price, 0),
});

export const useStore = create<AuthSlice & CartSlice>()((...a) => ({
  ...createAuthSlice(...a),
  ...createCartSlice(...a),
}));
Enter fullscreen mode Exit fullscreen mode

2. persist — Automatic LocalStorage Sync

import { persist, createJSONStorage } from "zustand/middleware";

const useSettings = create(
  persist(
    (set) => ({
      theme: "light",
      language: "en",
      setTheme: (theme: string) => set({ theme }),
    }),
    {
      name: "user-settings",
      storage: createJSONStorage(() => sessionStorage),
      partialize: (state) => ({ theme: state.theme }),
    }
  )
);
Enter fullscreen mode Exit fullscreen mode

3. subscribeWithSelector — Fine-Grained Subscriptions

import { subscribeWithSelector } from "zustand/middleware";

const useStore = create(
  subscribeWithSelector((set) => ({
    count: 0,
    name: "default",
    increment: () => set((s) => ({ count: s.count + 1 })),
  }))
);

// Subscribe to specific field changes
useStore.subscribe(
  (state) => state.count,
  (count, prevCount) => {
    console.log(`Count changed: ${prevCount} -> ${count}`);
    if (count > 100) analytics.track("high-count");
  }
);
Enter fullscreen mode Exit fullscreen mode

4. immer — Mutable-Style Updates

import { immer } from "zustand/middleware/immer";

const useStore = create(
  immer((set) => ({
    deeply: { nested: { items: [{ id: 1, done: false }] } },
    toggleItem: (id: number) => set((state) => {
      const item = state.deeply.nested.items.find((i) => i.id === id);
      if (item) item.done = !item.done;
    }),
  }))
);
Enter fullscreen mode Exit fullscreen mode

5. useStore with Selectors — Prevent Re-Renders

import { useShallow } from "zustand/react/shallow";

// BAD: re-renders on ANY state change
const { name, email } = useStore();

// GOOD: only re-renders when name or email change
const { name, email } = useStore(useShallow((s) => ({ name: s.name, email: s.email })));

// BEST: single value selector
const count = useStore((s) => s.count);
Enter fullscreen mode Exit fullscreen mode

Getting Started

npm install zustand
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)