useReducer 是 React 提供的一个内置 Hook,用于在函数组件中管理复杂的状态逻辑。它类似于 Redux 的简化版,适用于状态更新逻辑较复杂、多个子值依赖彼此、或需要可预测状态变化的场景。
一、基本使用方法
1. 语法
const [state, dispatch] = useReducer(reducer, initialState, init);
- reducer:一个纯函数,接收当前 state 和 action,返回新的 state。
- initialState:初始状态。
- init(可选) :用于惰性初始化的函数,
initialState = init(initialArg)
2. 示例
"use client"
import React, { useReducer } from 'react';
type actionType = {
type: string;
value?: any;
}
const initialState = {
count: 0,
name: 'Reducer Example',
};
const reducer = (state: any, action: actionType) => {
switch (action.type) {
case 'count':
return { ...state, count: action.value };
case 'name':
return { ...state, name: action.value };
default:
return state;
}
};
const ReducerPage = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return <div>
<h1>{state.name}</h1>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'count', value: state.count + 1 })}>Increment Count</button>
<button
onClick={() => dispatch({
type: 'name',
value: `Updated Reducer Example: ${new Date().toLocaleTimeString()}`
})}
>
Change Name
</button>
</div>;
};
export default ReducerPage;
二、使用场景
1. 状态逻辑复杂
当 useState 难以维护(例如状态包含多个子属性、更新逻辑相互依赖)时,useReducer 更清晰。
2. 多个组件共享状态更新逻辑
配合 useContext 可实现“类 Redux” 的全局状态管理,避免 props drilling。
3. 需要可预测、可测试的状态转换
reducer 是纯函数,便于单元测试;所有状态变更通过 dispatch(action) 触发,便于追踪。
4. 表单状态管理
如多步骤表单、动态字段增删等,用 useReducer 可集中处理字段变更、验证、重置等逻辑。
三、注意事项
1. reducer 必须是纯函数
- 不能有副作用(如 API 调用、直接修改 state)。
- 相同输入必须返回相同输出。
2. 不要直接修改 state
始终返回新对象,而不是修改原 state:
// ❌ 错误
state.count++;
return state;
// ✅ 正确
return { ...state, count: state.count + 1 };
3. 性能优化
- 如果 reducer 计算开销大,可考虑
useMemo缓存中间结果(但 reducer 本身通常很快)。 dispatch函数在组件 re-render 期间是稳定的(不会变),可安全用于依赖数组(如useEffect)。
4. 与 useState 的选择
- 简单状态 →
useState - 复杂状态逻辑、多个相关状态、需要集中管理 →
useReducer
5. 调试支持
可通过在 reducer 中加日志,或使用 React DevTools 查看 dispatch 的 action。
四、进阶:惰性初始化(Lazy Initialization)
如果初始状态计算开销大,可用第三个参数 init:
const init = (initialCount) => ({ count: initialCount });
function reducer(state, action) { /* ... */ }
function Counter({ initialCount }) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
}
这样 init 只在首次渲染时执行一次。
总结
| 特性 | useState | useReducer |
|---|---|---|
| 适用场景 | 简单独立状态 | 复杂、关联状态 |
| 状态更新 | 直接设值或函数 | 通过 dispatch(action) |
| 可读性 | 简单场景更直观 | 复杂逻辑更清晰 |
| 测试性 | 较弱 | 强(纯函数) |
合理使用 useReducer 能让状态管理更健壮、可维护。