Zustand State Management

Introduction

Zustand is a small global state library for React—stores hold shared data (auth, todos, UI flags) outside the component tree. It is simpler than Redux for many SPAs and maps closely to Vue Pinia. This chapter covers create, selectors, async actions, and when to use Zustand vs Context vs local state.

Prerequisites

Install

bash
npm install zustand

Basic Store

src/stores/counterStore.ts:

CounterDisplay.tsx:

Code explanation:

  • create returns a hook useCounterStore
  • Selectors (s) => s.count subscribe only to that slice—fewer re-renders
  • set merges partial state; functional form like useState

Todo Store (Preview)

src/stores/todoStore.ts:

Full UI in Todo project—sister to Vue Pinia Todo.

Async Actions

Persist Middleware (Concept)

bash
npm install zustand
tsx
import { create } from "zustand";
import { persist } from "zustand/middleware";
 
export const useTodoStore = create(
  persist<TodoState>(
    (set, get) => ({
      /* ... */
    }),
    { name: "hello-react-todos" }
  )
);

Warning

JWT in localStorage

Convenient for tutorials; production may prefer httpOnly cookies—see FastAPI JWT.

Zustand vs Context vs useState

NeedTool
One componentuseState
Theme, rare updatesContext
Todos, auth, cartZustand
Large enterprise with middlewareRedux Toolkit (external docs)

Outside React

tsx
const token = useAuthStore.getState().token;
useAuthStore.getState().logout();

Use sparingly—in router setup before React tree mounts.

FAQ

Subscribe to whole store?

tsx
const store = useCounterStore();  // re-renders on any change — avoid

Prefer selectors.

Immer for nested updates?

tsx
npm install immer
// zustand/middleware immer — optional for deep trees

Multiple stores?

Yes—useTodoStore, useAuthStore separate files.

Pinia migration mindset?

Pinia defineStore ≈ Zustand create; storeToRefs ≈ fine-grained selectors.

Next chapter?

Fetching API and CORS.