What is Zustand?
Zustand is a small, fast, and scalable state management library for React. It's built on a minimalistic API that's easy to learn and use, and it leverages React hooks to provide a simple way to manage your application's state without the boilerplate of more complex solutions like Redux.
The name "Zustand" is German for "state," which perfectly captures its purpose. It's designed to be unopinionated and gives you the freedom to organize your state as you see fit.
Why Choose Zustand?
- Minimal Boilerplate: Get up and running with just a few lines of code. No need for actions, reducers, or dispatchers for simple state changes.
- Hook-Based API: If you know React Hooks, you'll feel right at home with Zustand.
- Performance: Zustand only re-renders components when the state they subscribe to changes, leading to better performance.
- Small Bundle Size: It's a lightweight library that won't add much to your application's bundle size.
Getting Started with Zustand
First, you need to add Zustand to your project:
npm install zustand
Creating a Store
A "store" in Zustand is a hook that holds your state and the functions to update it. Here's how to create a simple store to manage a counter:
import { create } from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
export default useCounterStore;
In this example, create
is the core function from Zustand. It takes a function that receives a set
callback. This set
function is used to update the state.
Using the Store in a Component
Now, you can use your new useCounterStore
hook in any React component to access and update the state.
import React from 'react';
import useCounterStore from './useCounterStore';
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default Counter;
That's it! Your Counter
component is now connected to the Zustand store. When you call increment
or decrement
, the state will update, and the component will re-render to display the new count
.
Advanced Usage
Async Actions
Zustand makes it easy to handle asynchronous operations, like fetching data from an API.
import { create } from 'zustand';
const useUserStore = create((set) => ({
user: null,
loading: false,
fetchUser: async (userId) => {
set({ loading: true });
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const user = await response.json();
set({ user, loading: false });
} catch (error) {
set({ loading: false });
console.error('Failed to fetch user', error);
}
},
}));
Slices Pattern
For more complex state, you can split your store into "slices," which is a common pattern for better organization.
const createCounterSlice = (set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
});
const createThemeSlice = (set) => ({
theme: 'light',
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
});
const useBoundStore = create((...a) => ({
...createCounterSlice(...a),
...createThemeSlice(...a),
}));
By adopting Zustand, you can simplify your state management logic, reduce boilerplate, and improve the performance of your React applications. It's a powerful tool that scales with your project's needs.