Zustand
Zustand 是一个简单、快速、可扩展的状态管理库,用于 React 和 React Native 应用程序。它提供了一种创建全局状态的简便方法,而无需过多地关注 Redux 或 Context API 的复杂性。Zustand 的核心概念是创建一个存储(store),其中包含了应用程序的状态和可变更该状态的函数。

查看更多相关内容
如何创建和使用 Zustand store?### 创建 Zustand store 的步骤:
1. **安装 Zustand**:
```bash
npm install zustand
# 或
yarn add zustand
```
2. **创建 store 文件**(例如 `store.js`):
```javascript
import { create } from 'zustand';
const useStore = create((set) => ({
// 状态
count: 0,
user: null,
// 操作状态的方法
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
setUser: (user) => set({ user }),
reset: () => set({ count: 0, user: null })
}));
export default useStore;
```
3. **在组件中使用 store**:
```javascript
import React from 'react';
import useStore from './store';
function Counter() {
// 方法 1:获取整个 store
const { count, increment, decrement } = useStore();
// 方法 2:选择性订阅(推荐,性能更好)
const countValue = useStore((state) => state.count);
const incrementCount = useStore((state) => state.increment);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default Counter;
```
### 关键点:
* 使用 `create` 函数创建 store
* store 是一个函数,接收 `set` 和 `get` 两个参数
* `set` 用于更新状态,支持函数式更新
* 使用 `useStore` hook 在组件中访问状态
* 推荐使用选择性订阅来优化性能
服务端 · 3月7日 12:26
如何在 Zustand 中优化状态更新和性能?### Zustand 中的性能优化方法:
1. **选择性订阅**:
```javascript
// 不推荐:订阅整个 store,会导致组件在任何状态变化时都重渲染
const { count, user } = useStore();
// 推荐:只订阅需要的状态部分
const count = useStore((state) => state.count);
const user = useStore((state) => state.user);
```
2. **使用 shallow 比较**(对于复杂对象):
```javascript
import { create } from 'zustand';
import { shallow } from 'zustand/shallow';
// 订阅多个状态并使用 shallow 比较
const { count, user } = useStore(
(state) => ({ count: state.count, user: state.user }),
shallow // 只有当 count 或 user 真正变化时才重渲染
);
```
3. **状态拆分**:
```javascript
// 按功能拆分多个 store
// userStore.js
const useUserStore = create((set) => ({
user: null,
setUser: (user) => set({ user })
}));
// counterStore.js
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }))
}));
```
4. **使用 get 访问当前状态**(避免闭包陷阱):
```javascript
const useStore = create((set, get) => ({
count: 0,
// 推荐:使用 get 获取最新状态
increment: () => set((state) => ({ count: state.count + 1 })),
// 也可以使用 get
incrementAsync: async () => {
await someAsyncOperation();
set({ count: get().count + 1 });
}
}));
```
5. **批量更新**:
```javascript
// Zustand 会自动批量处理多个 set 调用
const updateMultiple = () => {
set({ count: 1 });
set({ user: { name: 'John' } });
// 只会触发一次重渲染
};
```
6. **避免在组件渲染时创建新函数**:
```javascript
// 不推荐:每次渲染都创建新函数
const incrementBy = (value) => useStore.getState().incrementBy(value);
// 推荐:在 store 中定义方法
// 在 store 中:
incrementBy: (value) => set((state) => ({ count: state.count + value }))
// 在组件中:
const incrementBy = useStore((state) => state.incrementBy);
```
### 关键点:
* 选择性订阅是 Zustand 性能优化的核心
* 使用 shallow 比较可以优化复杂对象的订阅
* 状态拆分可以减少不必要的重渲染
* 合理使用 get 可以避免闭包陷阱
* Zustand 会自动处理批量更新
服务端 · 3月7日 12:01
如何在 Zustand 中创建自定义中间件?在 Zustand 中创建自定义中间件非常灵活,可以用来实现各种功能,如日志记录、状态验证、性能监控等。
### 基本自定义中间件结构:
```javascript
const customMiddleware = (config) => (set, get, api) => {
// 在原始 store 之前执行的逻辑
const originalSet = set;
// 包装 set 函数
const wrappedSet = (partial, replace) => {
// 在状态更新前执行逻辑
console.log('State will update:', partial);
// 调用原始 set
const result = originalSet(partial, replace);
// 在状态更新后执行逻辑
console.log('State updated:', get());
return result;
};
// 创建 store
const store = config(wrappedSet, get, api);
// 返回增强后的 store
return store;
};
```
### 示例 1:日志中间件
```javascript
const loggerMiddleware = (config) => (set, get, api) => {
const originalSet = set;
const wrappedSet = (partial, replace) => {
const previousState = get();
const result = originalSet(partial, replace);
const nextState = get();
console.log('Previous state:', previousState);
console.log('Action:', partial);
console.log('Next state:', nextState);
return result;
};
return config(wrappedSet, get, api);
};
// 使用
const useStore = create(
loggerMiddleware((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }))
}))
);
```
### 示例 2:状态验证中间件
```javascript
const validationMiddleware = (schema) => (config) => (set, get, api) => {
const originalSet = set;
const wrappedSet = (partial, replace) => {
// 验证状态更新
const newState = typeof partial === 'function'
? partial(get())
: partial;
const validation = schema.safeParse({ ...get(), ...newState });
if (!validation.success) {
console.error('State validation failed:', validation.error);
throw new Error('Invalid state update');
}
return originalSet(partial, replace);
};
return config(wrappedSet, get, api);
};
// 使用
import { z } from 'zod';
const storeSchema = z.object({
count: z.number().min(0),
user: z.object({
id: z.string(),
name: z.string().min(1)
}).nullable()
});
const useStore = create(
validationMiddleware(storeSchema)((set) => ({
count: 0,
user: null,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: Math.max(0, state.count - 1) }))
}))
);
```
### 示例 3:性能监控中间件
```javascript
const performanceMiddleware = (config) => (set, get, api) => {
const originalSet = set;
const renderCounts = {};
const wrappedSet = (partial, replace) => {
const startTime = performance.now();
const result = originalSet(partial, replace);
const endTime = performance.now();
const duration = endTime - startTime;
if (duration > 10) {
console.warn(`Slow state update: ${duration.toFixed(2)}ms`, partial);
}
return result;
};
const store = config(wrappedSet, get, api);
// 跟踪组件渲染次数
const originalSubscribe = api.subscribe;
api.subscribe = (listener, selector) => {
const wrappedListener = (state, previousState) => {
const key = selector ? selector.toString() : 'full-store';
renderCounts[key] = (renderCounts[key] || 0) + 1;
if (renderCounts[key] % 10 === 0) {
console.log(`Render count for ${key}:`, renderCounts[key]);
}
listener(state, previousState);
};
return originalSubscribe(wrappedListener, selector);
};
return store;
};
// 使用
const useStore = create(
performanceMiddleware((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }))
}))
);
```
### 示例 4:撤销/重做中间件
```javascript
const undoRedoMiddleware = (config) => (set, get, api) => {
let history = [];
let future = [];
const MAX_HISTORY = 50;
const originalSet = set;
const wrappedSet = (partial, replace) => {
const previousState = get();
const result = originalSet(partial, replace);
const nextState = get();
// 保存到历史记录
history.push(previousState);
if (history.length > MAX_HISTORY) {
history.shift();
}
// 清空未来记录
future = [];
return result;
};
const store = config(wrappedSet, get, api);
// 添加撤销功能
store.undo = () => {
if (history.length === 0) return;
const previousState = history.pop();
future.push(get());
originalSet(previousState, true);
};
// 添加重做功能
store.redo = () => {
if (future.length === 0) return;
const nextState = future.pop();
history.push(get());
originalSet(nextState, true);
};
// 清空历史
store.clearHistory = () => {
history = [];
future = [];
};
return store;
};
// 使用
const useStore = create(
undoRedoMiddleware((set, get) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 }))
}))
);
// 在组件中使用
function Counter() {
const { count, increment, decrement } = useStore();
const undo = useStore((state) => state.undo);
const redo = useStore((state) => state.redo);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={undo}>Undo</button>
<button onClick={redo}>Redo</button>
</div>
);
}
```
### 关键点:
* 自定义中间件是一个高阶函数,接收 config 并返回新的配置函数
* 可以包装 set、get 和 api 来增强功能
* 中间件的执行顺序很重要,通常外层中间件先执行
* 可以在中间件中添加额外的功能,如日志、验证、性能监控等
* 中间件可以返回增强后的 store,添加新的方法或属性
服务端 · 3月7日 12:01
如何在 Zustand 中处理异步操作?### 在 Zustand 中处理异步操作的方法:
1. **基本异步操作**:
```javascript
import { create } from 'zustand';
const useStore = create((set, get) => ({
// 状态
user: null,
loading: false,
error: null,
// 异步操作
fetchUser: async (userId) => {
try {
set({ loading: true, error: null });
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
set({ user: userData, loading: false });
} catch (err) {
set({ error: err.message, loading: false });
}
},
// 另一种方式:使用 get 获取最新状态
updateUserProfile: async (updates) => {
try {
set({ loading: true, error: null });
const currentUser = get().user;
const response = await fetch(`/api/users/${currentUser.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
const updatedUser = await response.json();
set({ user: updatedUser, loading: false });
} catch (err) {
set({ error: err.message, loading: false });
}
}
}));
```
2. **使用 Promise 链**:
```javascript
const useStore = create((set) => ({
data: null,
status: 'idle', // idle, loading, success, error
fetchData: () => {
set({ status: 'loading' });
return fetch('/api/data')
.then((response) => response.json())
.then((data) => {
set({ data, status: 'success' });
return data;
})
.catch((error) => {
set({ error: error.message, status: 'error' });
throw error;
});
}
}));
```
3. **结合 React Query 或 SWR**:
```javascript
// 可以在 Zustand 中存储查询结果,同时使用 React Query 处理缓存和失效
import { create } from 'zustand';
import { useQuery } from 'react-query';
const useStore = create((set) => ({
user: null,
setUser: (user) => set({ user })
}));
// 在组件中
function UserProfile({ userId }) {
const { data, isLoading, error } = useQuery(
['user', userId],
() => fetch(`/api/users/${userId}`).then(res => res.json())
);
// 当查询成功时,更新 Zustand store
React.useEffect(() => {
if (data) {
useStore.getState().setUser(data);
}
}, [data]);
// 使用 Zustand 中的用户数据
const user = useStore(state => state.user);
return (
<div>
{isLoading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{user && <p>User: {user.name}</p>}
</div>
);
}
```
### 关键点:
* Zustand 支持直接在 store 方法中使用 async/await
* 可以在异步操作中管理 loading 和 error 状态
* 使用 `get()` 获取最新状态,避免闭包陷阱
* 可以返回 Promise 以便在组件中处理异步操作的结果
* 可以与 React Query 或 SWR 等库结合使用,获得更好的缓存和失效策略
服务端 · 3月7日 11:48
Zustand 中级面试题:如何对 Zustand store 进行单元测试?对 Zustand store 进行单元测试相对简单,因为 store 是纯 JavaScript 对象。
### 基本测试示例:
```javascript
// store.js
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
user: null,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
setUser: (user) => set({ user }),
reset: () => set({ count: 0, user: null })
}));
export default useStore;
```
```javascript
// store.test.js
import { renderHook, act } from '@testing-library/react';
import useStore from './store';
describe('Zustand Store', () => {
beforeEach(() => {
// 每个测试前重置 store
useStore.setState({ count: 0, user: null });
});
test('should initialize with default values', () => {
const { result } = renderHook(() => useStore());
expect(result.current.count).toBe(0);
expect(result.current.user).toBeNull();
});
test('should increment count', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
test('should decrement count', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.decrement();
});
expect(result.current.count).toBe(-1);
});
test('should set user', () => {
const { result } = renderHook(() => useStore());
const mockUser = { id: 1, name: 'John' };
act(() => {
result.current.setUser(mockUser);
});
expect(result.current.user).toEqual(mockUser);
});
test('should reset store', () => {
const { result } = renderHook(() => useStore());
const mockUser = { id: 1, name: 'John' };
act(() => {
result.current.setUser(mockUser);
result.current.increment();
});
expect(result.current.count).toBe(1);
expect(result.current.user).toEqual(mockUser);
act(() => {
result.current.reset();
});
expect(result.current.count).toBe(0);
expect(result.current.user).toBeNull();
});
});
```
### 测试异步操作:
```javascript
// store.js
const useStore = create((set) => ({
user: null,
loading: false,
error: null,
fetchUser: async (userId) => {
try {
set({ loading: true, error: null });
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
set({ user: userData, loading: false });
} catch (err) {
set({ error: err.message, loading: false });
}
}
}));
```
```javascript
// store.test.js
import { renderHook, act, waitFor } from '@testing-library/react';
import useStore from './store';
describe('Zustand Store - Async Operations', () => {
beforeEach(() => {
useStore.setState({ user: null, loading: false, error: null });
});
test('should fetch user successfully', async () => {
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, name: 'John' })
})
);
const { result } = renderHook(() => useStore());
await act(async () => {
await result.current.fetchUser(1);
});
expect(result.current.user).toEqual({ id: 1, name: 'John' });
expect(result.current.loading).toBe(false);
expect(result.current.error).toBeNull();
});
test('should handle fetch error', async () => {
global.fetch = jest.fn(() => Promise.reject(new Error('Network error')));
const { result } = renderHook(() => useStore());
await act(async () => {
await result.current.fetchUser(1);
});
expect(result.current.error).toBe('Network error');
expect(result.current.loading).toBe(false);
});
});
```
### 测试选择性订阅:
```javascript
import { renderHook } from '@testing-library/react';
import useStore from './store';
describe('Zustand Store - Selective Subscription', () => {
beforeEach(() => {
useStore.setState({ count: 0, user: null });
});
test('should only re-render when subscribed state changes', () => {
const renderCount = jest.fn();
const { result } = renderHook(() => {
renderCount();
return useStore((state) => state.count);
});
expect(renderCount).toHaveBeenCalledTimes(1);
act(() => {
useStore.getState().setUser({ id: 1, name: 'John' });
});
// 不应该重新渲染,因为 user 变化,但订阅的是 count
expect(renderCount).toHaveBeenCalledTimes(1);
act(() => {
useStore.getState().increment();
});
// 应该重新渲染,因为 count 变化
expect(renderCount).toHaveBeenCalledTimes(2);
});
});
```
### 关键点:
* 使用 `@testing-library/react` 的 `renderHook` 和 `act` 进行测试
* 在每个测试前重置 store 状态
* 对于异步操作,使用 `waitFor` 等待状态更新
* 测试选择性订阅时,验证重渲染次数
* 使用 `useStore.getState()` 直接访问和操作 store
服务端 · 3月7日 11:44
如何在 React Native 中使用 Zustand 管理状态?### React Native 中使用 Zustand 的方法:
1. **安装 Zustand**
```bash
npm install zustand
# 或
yarn add zustand
```
2. **创建 Store**
```javascript
import { create } from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
```
3. **在 React Native 组件中使用**
```javascript
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useCounterStore } from './store';
export default function CounterScreen() {
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
return (
<View style={styles.container}>
<Text style={styles.count}>{count}</Text>
<View style={styles.buttons}>
<TouchableOpacity style={styles.button} onPress={decrement}>
<Text style={styles.buttonText}>-</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={increment}>
<Text style={styles.buttonText}>+</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
count: {
fontSize: 48,
marginBottom: 20,
},
buttons: {
flexDirection: 'row',
gap: 20,
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 24,
fontWeight: 'bold',
},
});
```
4. **持久化状态**
- 使用 persist 中间件保存状态到 AsyncStorage
- 示例:
```javascript
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
const useUserStore = create(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
}),
{
name: 'user-storage',
storage: {
getItem: async (name) => {
const item = await AsyncStorage.getItem(name);
return item ? JSON.parse(item) : null;
},
setItem: async (name, value) => {
await AsyncStorage.setItem(name, JSON.stringify(value));
},
removeItem: async (name) => {
await AsyncStorage.removeItem(name);
},
},
}
)
);
```
5. **React Native 特定优化**
- 避免在选择器中使用复杂计算
- 合理使用 useCallback 缓存回调函数
- 注意 AsyncStorage 的性能影响
6. **常见使用场景**
- 用户认证状态管理
- 应用设置和偏好
- 购物车状态
- 导航状态管理
服务端 · 3月7日 11:44
Zustand 与 Redux 相比有哪些主要区别?### Zustand 与 Redux 的核心区别:
1. **API 复杂度**
- **Zustand**:简洁的函数式 API,无需 action types、reducers、dispatch 等概念
- **Redux**:需要定义 action types、reducers、使用 dispatch 分发 actions
2. **代码量**
- **Zustand**:最小化样板代码,几行代码即可创建 store
- **Redux**:需要更多的样板代码,包括 actions、reducers、store 配置等
3. **Provider 需求**
- **Zustand**:无需 Provider 组件,直接使用 hook
- **Redux**:需要在应用顶层包裹 Provider 组件
4. **状态更新**
- **Zustand**:直接使用 set 函数更新状态,支持函数式更新
- **Redux**:通过 dispatch actions,由 reducers 处理状态更新
5. **中间件**
- **Zustand**:内置支持中间件,如 persist、devtools 等
- **Redux**:需要单独安装中间件,如 redux-thunk、redux-saga 等
6. **性能优化**
- **Zustand**:自动优化重渲染,只订阅需要的状态
- **Redux**:需要手动使用 selectors 优化性能
7. **类型安全**
- **Zustand**:良好的 TypeScript 支持,类型推断更简单
- **Redux**:需要更多的类型定义,如 action types、reducer types 等
8. **适用场景**
- **Zustand**:适合中小型应用,快速开发
- **Redux**:适合大型应用,需要严格的状态管理规范
### 选择建议:
- 小型项目或原型开发:优先选择 Zustand
- 大型企业应用:可以考虑 Redux(尤其是需要中间件生态)
- 性能敏感的应用:Zustand 可能更有优势
- 团队熟悉度:考虑团队对不同库的熟悉程度
服务端 · 3月7日 11:44
如何在 Zustand 中使用 TypeScript 确保类型安全?### Zustand 中使用 TypeScript 的方法:
1. **定义状态类型**
```typescript
interface UserState {
user: {
id: string;
name: string;
email: string;
} | null;
isLoading: boolean;
error: string | null;
setUser: (user: UserState['user']) => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
logout: () => void;
}
```
2. **创建类型化的 Store**
```typescript
import { create } from 'zustand';
const useUserStore = create<UserState>((set) => ({
user: null,
isLoading: false,
error: null,
setUser: (user) => set({ user }),
setLoading: (loading) => set({ loading }),
setError: (error) => set({ error }),
logout: () => set({ user: null, error: null }),
}));
```
3. **在组件中使用**
```typescript
import { useUserStore } from './store';
function UserProfile() {
const user = useUserStore((state) => state.user);
const isLoading = useUserStore((state) => state.isLoading);
const error = useUserStore((state) => state.error);
const logout = useUserStore((state) => state.logout);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!user) return <div>Please login</div>;
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>Email: {user.email}</p>
<button onClick={logout}>Logout</button>
</div>
);
}
```
4. **类型推断和自动补全**
- TypeScript 会自动推断状态和操作的类型
- 编辑器会提供智能提示和类型检查
5. **复杂状态类型**
- 对于嵌套状态,可以使用嵌套接口
- 对于动态状态,可以使用泛型
6. **中间件的类型支持**
- persist 中间件的类型配置
- 自定义中间件的类型定义
### 最佳实践:
- 为每个 store 创建单独的类型定义文件
- 使用接口明确状态结构和操作签名
- 利用 TypeScript 的类型检查捕获潜在错误
- 结合泛型处理复杂的状态类型
服务端 · 3月7日 11:44
如何在 Zustand 中处理异步操作?### Zustand 中处理异步操作的方法:
1. **基本异步操作**
- 在 store 中定义异步 action
- 使用 async/await 语法
- 示例:
```javascript
import { create } from 'zustand';
const useUserStore = create((set) => ({
user: null,
isLoading: false,
error: null,
fetchUser: async (userId) => {
set({ isLoading: true, error: null });
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const user = await response.json();
set({ user, isLoading: false });
} catch (error) {
set({ error: error.message, isLoading: false });
}
},
}));
```
2. **使用 Promise**
- 返回 Promise 以便组件可以等待操作完成
- 示例:
```javascript
fetchUser: async (userId) => {
set({ isLoading: true, error: null });
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const user = await response.json();
set({ user, isLoading: false });
return user; // 返回结果
} catch (error) {
set({ error: error.message, isLoading: false });
throw error; // 抛出错误
}
},
```
3. **处理多个异步操作**
- 并行执行多个异步操作
- 示例:
```javascript
fetchMultipleData: async () => {
set({ isLoading: true });
try {
const [user, posts] = await Promise.all([
fetch('https://api.example.com/user').then(res => res.json()),
fetch('https://api.example.com/posts').then(res => res.json())
]);
set({ user, posts, isLoading: false });
} catch (error) {
set({ error: error.message, isLoading: false });
}
},
```
4. **中间件处理**
- 使用自定义中间件处理异步操作
- 示例:
```javascript
const asyncMiddleware = (store) => (next) => (action) => {
if (typeof action === 'function') {
return action(store.getState, store.setState);
}
return next(action);
};
const useStore = create(
asyncMiddleware((set, get) => ({
// 状态和操作
}))
);
```
5. **最佳实践**
- 始终处理加载状态和错误状态
- 为异步操作提供取消机制
- 合理使用 try/catch 捕获错误
- 考虑使用 SWR 或 React Query 处理复杂的异步数据
6. **常见异步场景**
- API 调用
- 数据加载和缓存
- 文件上传下载
- 认证和授权操作
服务端 · 3月7日 11:44
Zustand 的中间件有哪些,如何使用它们?### Zustand 常用中间件:
1. **persist 中间件**
- 功能:将状态持久化到 localStorage、sessionStorage 或自定义存储
- 使用场景:需要保持用户登录状态、用户偏好设置等
- 示例:
```javascript
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useStore = create(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
}),
{
name: 'user-storage', // 存储名称
}
)
);
```
2. **devtools 中间件**
- 功能:集成 Redux DevTools,方便调试状态变化
- 使用场景:开发环境中调试状态管理
- 示例:
```javascript
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
})
)
);
```
3. **immer 中间件**
- 功能:使用 Immer 库简化不可变状态更新
- 使用场景:处理复杂的嵌套状态更新
- 示例:
```javascript
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
const useStore = create(
immer((set) => ({
user: { name: 'John', age: 30 },
updateName: (name) =>
set((state) => {
state.user.name = name;
}),
}))
);
```
4. **combine 中间件**
- 功能:组合多个状态切片
- 使用场景:模块化管理复杂状态
### 中间件组合使用:
```javascript
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';
const useStore = create(
devtools(
persist(
(set) => ({
// 状态和操作
}),
{ name: 'app-storage' }
)
)
);
```
### 自定义中间件:
可以根据需要创建自定义中间件,例如日志记录、性能监控等。
服务端 · 3月7日 11:43