State management is one of the trickiest parts of building complex React apps. From useState
to Redux, we’ve all explored different tools to keep our app's state clean and maintainable.
But over time, many developers—myself included—found that Redux became too verbose and Context API too limited.
That’s where Zustand comes in.
Zustand (German for "state") is a fast, small, and scalable state management solution built by the creators of Jotai and React Spring.
Zustand makes managing state feel like plain JavaScript again.
First, install Zustand:
npm install zustand
Zustand revolves around the idea of a centralized store holding your state and actions. You create a store using the create
function:
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
You can then use this store in your React components as a hook:
function Counter() {
const { count, increment, decrement } = useStore();
return (
<>
<h1>{count}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
}
Zustand has excellent TypeScript support. Define the shape of your state and actions using interfaces or types, then pass it as a generic to create
:
import { create } from 'zustand';
type CounterState = {
count: number;
increment: () => void;
decrement: () => void;
};
const useStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
This ensures type safety and auto-completion in your components.
Zustand supports powerful middleware such as persist
for state persistence and devtools
for debugging.
To persist your state in local storage (or other storage), use the persist
middleware:
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
type BearState = {
bears: number;
addBear: () => void;
};
const useBearStore = create<BearState>()(
persist(
(set, get) => ({
bears: 0,
addBear: () => set({ bears: get().bears + 1 }),
}),
{
name: 'bear-storage', // unique key in storage
}
)
);
Your state will survive page reloads or browser restarts with this setup.
For enhanced debugging with Redux DevTools extension, wrap your store creator with devtools
:
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
);
You can even combine middleware like this:
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
const useStore = create(
devtools(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}),
{ name: 'count-storage' }
)
)
);
Zustand is perfect for:
Zustand offers a minimalist yet powerful approach to managing React app state, bridging the gap between local state hooks and heavyweight solutions like Redux. It brings the power of a centralized store with the simplicity of JavaScript, making state management cleaner and more maintainable across projects of all sizes.
Zustand is a game-changer for state management in React. It gives you the power of Redux without the boilerplate, and the simplicity of Context API with better performance.
If you’re tired of verbose reducers and boilerplate, give Zustand a try—it may quickly become your go-to state management tool.
I'm always looking for new and exciting projects to work on. If you have any questions, please don't hesitate to contact me.
Help you create experiences where aesthetics & functionality seamlessly come together.