1. 使用痛点:useState 像散装零钱,hold 不住大钱账
说句大实话:用 useState 也能写,但复杂了就难受。
你是不是也遇到过这些场景?
- 一个组件里七八个 useState,变量名开始失控,
userName、userName2、userNameFinal…… - 金额、权限这类敏感字段,万一哪天手抖写错,直接背锅,老板都救不了你。
- 表单、撤销、异步三件套,逻辑一交叉,代码就像毛线团,谁都不敢动。
写到这里,你是不是已经开始“恐惧”,迫切想知道怎么优雅解决?
2. API 对照
别怕,先看两段代码,长得其实差不多:
| useState(你熟悉的) | useReducer(升级版) |
|---|---|
const [count, setCount] = useState(0) | const [state, dispatch] = useReducer(reducer, initialState) |
其实只是把 setCount 换成了 dispatch,别有心理负担!
再来三个新名词的生活化解释:
initialState就是“账本首页”,所有数据都记在这。reducer是“会计规则”,规定每一笔账怎么记。dispatch像“提交报销单”,你只管填单,怎么记账交给会计。
3️⃣ 原理解码:魂斗罗式双人配合
想象你在玩魂斗罗:
- 你按下按钮(dispatch),发出一个 action(子弹)。
- reducer 是“第二玩家”,接住子弹后,按既定规则开火。
- 最终返回的新 state,就是“敌人被干掉”的结果。
注意:reducer 必须是纯函数!
同样的动作、同样的旧账,必须算出同样的新账,否则会计就“做假账”了。
这就是 useReducer 可预测、可测试的底层保障。
4️⃣ 场景实战:三段 20 行代码,拿来即用
① 复杂表单:十几个字段,一个 reducer 全搞定
const initialState = { name: '', age: '', email: '' };
function formReducer(state, action) {
return { ...state, [action.field]: action.value };
}
const [form, dispatch] = useReducer(formReducer, initialState);
// 用法
<input onChange={e => dispatch({ field: 'name', value: e.target.value })} />
✓ 好处:字段再多也只需一个 dispatch,代码清爽。
② 撤销/重做:历史账本,UNDO/REDO 秒切换
const initialState = { past: [], present: 0, future: [] };
function reducer(state, action) {
switch (action.type) {
case 'UNDO':
if (!state.past.length) return state;
return {
past: state.past.slice(0, -1),
present: state.past[state.past.length - 1],
future: [state.present, ...state.future]
};
case 'REDO':
if (!state.future.length) return state;
return {
past: [...state.past, state.present],
present: state.future[0],
future: state.future.slice(1)
};
default:
return state;
}
}
✓ 好处:撤销、重做只需两个 action,历史账本随时翻。
③ 异步请求:三板斧,状态流转一目了然
const initialState = { loading: false, data: null, error: null };
function fetchReducer(state, action) {
switch (action.type) {
case 'FETCH_START': return { ...state, loading: true, error: null };
case 'FETCH_SUCCESS': return { ...state, loading: false, data: action.data };
case 'FETCH_ERROR': return { ...state, loading: false, error: action.error };
default: return state;
}
}
✓ 好处:加载、成功、失败状态分明,逻辑像人话一样清晰。
5️⃣ 收尾口诀:一句人话 + 官方指路
把钱交给会计,不怕手抖;把状态交给 useReducer,不怕 bug。
React useReducer 官方文档