📌 开篇:为什么需要 useReducer?
在 React 开发中,我们通常使用 useState
来管理组件的状态。但随着状态逻辑变得复杂(例如多个状态相互依赖、状态更新逻辑分散),useState
可能变得难以维护。
useReducer
是 React 提供的一个更强大的状态管理 Hook ,它借鉴了 Redux 的思想,适用于:
✅ 复杂的状态逻辑 (如多个状态联动)
✅ 可预测的状态更新 (类似 Redux 的 reducer 模式)
✅ 更清晰的代码结构 (避免分散的 setState
调用)
本文将通过 通俗易懂的讲解 + 代码示例 + 示意图 ,带你彻底掌握 useReducer
!
📝 正文:useReducer 基础用法
1. useReducer 基本语法
useReducer
接受两个参数:
reducer
函数:定义如何更新状态initialState
:初始状态
并返回:
- 当前状态
state
dispatch
方法:用于触发状态更新
javascript
import { useReducer } from 'react';
// 定义 reducer 函数
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
// 使用 useReducer
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
</div>
);
}
📌 运行效果:
(示意图:点击按钮时,count
会根据 action.type
增减)
2. useReducer vs useState 对比
特性 | useState |
useReducer |
---|---|---|
适用场景 | 简单状态 | 复杂状态逻辑 |
代码组织 | 分散 | 集中管理 |
可维护性 | 低(逻辑复杂时) | 高 |
类似概念 | 直接赋值 | Redux 风格 |
📌 何时选择 useReducer
?
- 状态更新逻辑复杂(如多个
useState
相互依赖) - 需要更清晰的状态管理(如表单、购物车、游戏状态)
3. 实战示例:TodoList 应用
javascript
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, { text: action.text, completed: false }];
case 'TOGGLE_TODO':
return state.map((todo, index) =>
index === action.index ? { ...todo, completed: !todo.completed } : todo
);
default:
return state;
}
}
function TodoList() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [input, setInput] = useState('');
const handleAddTodo = () => {
if (input.trim()) {
dispatch({ type: 'ADD_TODO', text: input });
setInput('');
}
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a new task"
/>
<button onClick={handleAddTodo}>Add</button>
<ul>
{todos.map((todo, index) => (
<li
key={index}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
onClick={() => dispatch({ type: 'TOGGLE_TODO', index })}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
📌 运行效果:
(示意图:可以添加任务,点击任务切换完成状态)
🔍 深入理解:useReducer 高级技巧
1. 结合 useContext 实现全局状态管理
useReducer
+ useContext
可以替代 Redux,实现轻量级全局状态管理:
javascript
// 1. 创建 Context
const TodoContext = createContext();
function App() {
const [todos, dispatch] = useReducer(todoReducer, []);
return (
<TodoContext.Provider value={{ todos, dispatch }}>
<TodoList />
<TodoStats /> {/* 另一个组件可以访问 todos */}
</TodoContext.Provider>
);
}
// 2. 在子组件中使用
function TodoStats() {
const { todos } = useContext(TodoContext);
return <div>Total todos: {todos.length}</div>;
}
2. 使用 Immer 优化不可变更新
在 reducer
中直接修改 state
会导致问题,可以使用 Immer
简化不可变更新:
javascript
import { produce } from 'immer';
function todoReducer(state, action) {
return produce(state, (draft) => {
switch (action.type) {
case 'ADD_TODO':
draft.push({ text: action.text, completed: false });
break;
case 'TOGGLE_TODO':
draft[action.index].completed = !draft[action.index].completed;
break;
}
});
}
🎯 总结:useReducer 核心要点
✔ 适合复杂状态逻辑 ,比 useState
更易于维护。
✔ 类似 Redux 的 reducer 模式 ,但更轻量级。
✔ 可结合 useContext
实现全局状态管理 。
✔ 推荐使用 Immer 优化不可变更新。
📌 适用场景:
- 表单管理(多字段联动)
- 购物车状态
- 游戏状态管理
- 全局状态(替代 Redux)
希望这篇文章能帮助你掌握 useReducer
!🚀 如果有疑问,欢迎在评论区讨论!
别把忙当成不知为何而活的障眼法。