Goodbye Redux Boilerplate? A Detailed Guide to the Lightweight Zustand State Manager

3 min

1. The “Trouble” with Redux

Redux is unquestionably the best-known and most powerful state-management library in the React ecosystem. Features such as unidirectional data flow and time-travel debugging make it a reliable choice for large, complex applications. For many small and medium-sized projects, however, Redux’s “boilerplate” is often a headache:

  • Actions & Action Creators: Defining many action types and creator functions.
  • Reducers: Writing large switch statements to handle different actions.
  • Dispatch & Selectors: Dispatching actions with dispatch and subscribing to state changes with useSelector inside components.
  • Context Provider: Wrapping the application root in a <Provider>.

All of this means that adding even a simple piece of state requires changes across several files, making the process cumbersome.

2. Zustand: A Breath of Fresh Air

Zustand (German for “state”) is a lightweight state-management library developed by the Poimandres team, the creators of react-three-fiber. Its design philosophy is minimalism and non-intrusiveness.

Core features:

  • Very little code: Implementing a feature with Zustand usually requires only a fraction of the code needed with Redux.
  • Hooks-based: Everything revolves around a custom Hook, fitting naturally into modern React development.
  • No Context Provider required: You do not need to wrap the top level of the application in any Provider. The store is independent of the component tree and can be imported and used anywhere.
  • Easy to learn: The API is extremely simple, and its core usage can be learned in minutes.

3. Core Usage

Using Zustand involves two steps: creating a Store and using it in a component.

a. Creating a Store

You can define a store in any .js or .ts file.

// src/store.js
import { create } from 'zustand';

const useBearStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
}));

export default useBearStore;

The create function receives a callback whose argument is the set function, similar to React’s setState. This is where you define your state and the methods that update it.

b. Using It in a Component

Use it in any component just like an ordinary Hook.

// src/components/BearCounter.jsx
import useBearStore from '../store';

function BearCounter() {
  const bears = useBearStore((state) => state.bears);
  return <h1>{bears} around here ...</h1>;
}

Notice that we subscribe through the selector function (state) => state.bears to the bears state. This is important because it ensures that the component rerenders only when bears changes, avoiding unnecessary performance costs.

// src/components/Controls.jsx
import useBearStore from '../store';

function Controls() {
  const increasePopulation = useBearStore((state) => state.increasePopulation);
  return <button onClick={increasePopulation}>one up</button>;
}

Getting an action is just as simple.

4. Asynchronous Actions

Zustand also handles asynchronous operations naturally. You do not need middleware such as redux-thunk or redux-saga.

const useAsyncStore = create((set) => ({
  data: null,
  fetchData: async (url) => {
    const response = await fetch(url);
    const data = await response.json();
    set({ data });
  },
}));

Conclusion

Zustand is not intended to replace Redux completely. Redux still has advantages in strict conventions, traceability, and its vast ecosystem.

For the overwhelming majority of React applications, however, Zustand offers a simpler and faster choice with less mental overhead. If you are tired of Redux’s formalities, or your next project needs a nimble and flexible state manager, Zustand is certainly an excellent option worth trying.