๐Ÿป

Zustand

Bear necessities for state management

v4.5.0BeginnerState ManagementHooksSimpleTypeScript

Overview

Zustand is a small, fast, and scalable bearbones state-management solution. It has a simple API based on hooks that doesn't require wrapping your app in a Provider.

Key features: - No boilerplate code - No need for context providers - Works with React DevTools - Full TypeScript support - Middleware support (persist, devtools, etc.)

Basic Store

store/bearStore.ts
1400">import { create } 400">from 'zustand';
2 
3interface BearState {
4 bears: 400">number;
5 increase: () => 400">void;
6 decrease: () => 400">void;
7}
8 
9400">const useBearStore = create<BearState>((400">set) => ({
10 bears: 0,
11 increase: () => 400">set((state) => ({ bears: state.bears + 1 })),
12 decrease: () => 400">set((state) => ({ bears: state.bears - 1 })),
13}));
14 
15// In component
16400">function 300">BearCounter() {
17 400">const bears = 300">useBearStore((state) => state.bears);
18 400">const increase = 300">useBearStore((state) => state.increase);
19
20 400">return (
21 <div>
22 <h1>{bears} bears</h1>
23 <button onClick={increase}>Add bear</button>
24 </div>
25 );
26}

Installation

Quick Install

Terminal
1-amber-400">npm install zustand

Requirements

  • React 18+

Setup Steps

  1. 1Install Zustand: npm install zustand
  2. 2Create a store file
  3. 3Import and use the store in components

Creating Stores

Zustand stores are created using the `create` function. The store holds state and actions to update it.

Store with TypeScript

store/userStore.ts
1400">import { create } 400">from 'zustand';
2 
3interface User {
4 id: 400">string;
5 name: 400">string;
6 email: 400">string;
7}
8 
9interface UserState {
10 user: User | 400">null;
11 isLoading: 400">boolean;
12 error: 400">string | 400">null;
13 login: (email: 400">string, password: 400">string) => 400">Promise<400">void>;
14 logout: () => 400">void;
15}
16 
17400">const useUserStore = create<UserState>((400">set) => ({
18 user: 400">null,
19 isLoading: 400">false,
20 error: 400">null,
21
22 login: 400">async (email, password) => {
23 400">set({ isLoading: 400">true, error: 400">null });
24 400">try {
25 400">const response = 400">await 300">fetch('/api/login', {
26 method: 'POST',
27 body: JSON.300">stringify({ email, password }),
28 });
29 400">const user = 400">await response.300">json();
30 400">set({ user, isLoading: 400">false });
31 } 400">catch (error) {
32 400">set({ error: 'Login failed', isLoading: 400">false });
33 }
34 },
35
36 logout: () => 400">set({ user: 400">null }),
37}));

Best Practices

  • Select only the state you need to prevent unnecessary re-renders
  • Use TypeScript interfaces for type safety
  • Keep stores small and focused
  • Use middleware for persistence and devtools
  • Consider using slices for large applications

Common Pitfalls

โš ๏ธSelecting the entire state instead of specific slices
โš ๏ธNot using TypeScript for type safety
โš ๏ธCreating stores inside components

Code Snippets

Persist Middleware

intermediate

Persist state to localStorage

TypeScript
1400">import { create } 400">from 'zustand';
2400">import { persist } 400">from 'zustand/middleware';
3 
4400">const useStore = 300">create(
5 300">persist(
6 (400">set) => ({
7 count: 0,
8 increment: () => 400">set((state) => ({ count: state.count + 1 })),
9 }),
10 {
11 name: 'my-storage', // localStorage key
12 }
13 )
14);

Resources

Related Technologies