Zustand is a small, fast, and scalable state management solution for React. It is an excellent alternative to more complex state management libraries like Redux. Zustands's API is minimalistic, and it's highly performant, making it a good choice for managing global state in React applications.
Key Features of Zustand:
- Minimal boilerplate: No need to define actions or reducers.
- Simple API: Just create a store and use it.
- Reactivity: Components automatically re-render when the state they depend on changes.
- Performance: Zustand uses hooks internally to minimize unnecessary re-renders.
Setting Up Zustand in a React Application
Let's go through how to set up and use Zustand in a React app for global state management.
1. Install Zustand
You can install Zustand via npm or yarn:
npm install zustand
or
yarn add zustand
2. Create a Store with Zustand
In Zustand, you define a store using the create
function, which takes a function that returns the state object.
Here’s an example of a simple store that manages a counter and a theme (light or dark).
import create from 'zustand'
// Create a store
const useStore = create((set) => ({
count: 0, // state variable
theme: 'light', // state variable for theme
increment: () => set((state) => ({ count: state.count + 1 })), // action to increment count
decrement: () => set((state) => ({ count: state.count - 1 })), // action to decrement count
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })), // toggle between light/dark theme
}))
In this example:
count
is the state variable.increment
anddecrement
are actions that update thecount
state.theme
is another state variable for the current theme (either 'light' or 'dark').toggleTheme
is an action to toggle the theme.
3. Using the Store in Components
You can use the store in your components with the useStore
hook. Components that use state from the store will automatically re-render when the state changes.
Example: Counter Component
import React from 'react'
import { useStore } from './store' // import your Zustand store
function Counter() {
const { count, increment, decrement } = useStore((state) => ({
count: state.count,
increment: state.increment,
decrement: state.decrement,
}))
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
export default Counter
Example: Theme Toggle Component
import React from 'react'
import { useStore } from './store' // import your Zustand store
function ThemeToggle() {
const { theme, toggleTheme } = useStore((state) => ({
theme: state.theme,
toggleTheme: state.toggleTheme,
}))
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
)
}
export default ThemeToggle
4. Connecting Zustand to Your Application
You can now use the Counter
and ThemeToggle
components in your app, and they will have access to the shared global state.
import React from 'react'
import Counter from './Counter'
import ThemeToggle from './ThemeToggle'
function App() {
return (
<div>
<h1>My Zustand App</h1>
<Counter />
<ThemeToggle />
</div>
)
}
export default App
5. Persisting State Across Reloads (Optional)
Zustand supports state persistence using middleware. You can use the persist
middleware to store the state in localStorage
or sessionStorage
.
Example: Persisting the theme
state
import create from 'zustand'
import { persist } from 'zustand/middleware'
const useStore = create(
persist(
(set) => ({
count: 0,
theme: 'light',
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
}),
{
name: 'my-app-storage', // the name of the storage key
getStorage: () => localStorage, // storage type (localStorage or sessionStorage)
}
)
)
With this middleware, the theme
and other state variables will persist across page reloads.
6. Using Zustand in Large Applications
As your application grows, you might want to organize your stores by dividing them into multiple smaller stores based on feature areas (e.g., user, settings, etc.). Zustand allows you to create multiple stores and combine them into one. Here's an example:
Example: Multiple Stores
// store/userStore.js
import create from 'zustand'
export const useUserStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
}))
// store/settingsStore.js
import create from 'zustand'
export const useSettingsStore = create((set) => ({
theme: 'light',
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
}))
You can then use both stores in your components:
import { useUserStore } from './store/userStore'
import { useSettingsStore } from './store/settingsStore'
function App() {
const { user, setUser } = useUserStore((state) => ({
user: state.user,
setUser: state.setUser,
}))
const { theme, toggleTheme } = useSettingsStore((state) => ({
theme: state.theme,
toggleTheme: state.toggleTheme,
}))
return (
<div>
<h1>User: {user ? user.name : 'Guest'}</h1>
<button onClick={() => setUser({ name: 'John Doe' })}>Set User</button>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
)
}
Conclusion
Zustand is a simple and powerful state management library for React. It provides an easy-to-use API with minimal setup, making it great for small to large applications. By following the steps above, you can manage global state effectively using Zustand and even extend it for more complex use cases.