๐ป
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 component16400">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 zustandRequirements
- React 18+
Setup Steps
- 1Install Zustand: npm install zustand
- 2Create a store file
- 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
intermediatePersist 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 key12 }13 )14);