← Back to React Course | Chapter 9: State Management | Lesson 7 of 10

State Management with Zustand

Zustand is like a sticky note pinned to the fridge that anyone in the house can read and update directly, without needing a formal meeting (unlike Redux's more structured process).

Creating a Zustand Store

Zustand's create() function defines a store in one step: you provide a function that receives set (for updating state) and returns the initial state plus any update functions, all in one plain object — no separate actions, reducers, or types required.

Note: Unlike Redux, there's no Provider needed — the store created by create() is just a React hook you can import and call anywhere.

Warning: Define the store once at module scope (outside any component) — creating it inside a component would reset it on every render.

Example: Creating a Zustand Store

markup
// Run in your local React project (npm install required)
import { create } from 'zustand';

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

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Using the Store in a Component

A Zustand store is used just like any other custom hook. Calling useCounterStore(state => state.count) subscribes the component to just that field, re-rendering only when it changes — similar in spirit to Redux's useSelector, but built directly into the store hook itself.

Note: Select only the specific fields/functions you need, rather than the whole store object, to avoid unnecessary re-renders.

Warning: Calling useCounterStore() with no selector returns the ENTIRE store state, re-rendering the component on any change to any field.

Example: Using the Store in a Component

markup
// Run in your local React project (npm install required)
function Counter() {
  const count = useCounterStore(state => state.count);
  const increment = useCounterStore(state => state.increment);
  return <button onClick={increment}>Count: {count}</button>;
}

Zustand vs. Redux

Zustand trades some of Redux's strict structure (separate actions/reducers/types) for a much smaller, more direct API, making it faster to get started with for small-to-medium apps. Redux's stricter conventions can pay off more in very large teams/codebases where that structure aids consistency.

Note: If a team is used to Redux's patterns and DevTools workflow, that familiarity is worth weighing against Zustand's smaller learning curve.

Warning: Zustand's flexibility means there's less enforced structure — larger Zustand codebases benefit from establishing their own conventions for organizing stores.

Example: Zustand vs. Redux

markup
// Run in your local React project (npm install required)
// Redux: separate action, reducer, dispatch, Provider, useSelector/useDispatch
// Zustand: one create() call, no Provider, direct hook usage:
const useStore = create(set => ({
  user: null,
  login: name => set({ user: name }),
}));
function Profile() {
  const user = useStore(s => s.user);
  return <p>{user || "Not logged in"}</p>;
}
Common Mistakes
  1. Selecting the entire store object in a component instead of just the specific field needed, causing extra re-renders.
  2. Mutating state directly outside of the store's set function.
  3. Creating a new store instance inside a component instead of defining it once at module scope.
Chapter Summary
  • Zustand is a minimal state-management library with far less boilerplate than Redux.
  • A store is created with the create() function, defining state and update functions together.
  • Components read from the store by calling the store hook with a selector function.
  • No Provider component is required — the store is just a hook you import and use directly.
Browser Support

Requires npm install zustand — not available via CDN in this sandbox.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.