useReducer:让你的 React 状态管理不再“散装零钱”

50 阅读2分钟

1. 使用痛点:useState 像散装零钱,hold 不住大钱账

说句大实话:用 useState 也能写,但复杂了就难受。
你是不是也遇到过这些场景?

  • 一个组件里七八个 useState,变量名开始失控,userNameuserName2userNameFinal……
  • 金额、权限这类敏感字段,万一哪天手抖写错,直接背锅,老板都救不了你。
  • 表单、撤销、异步三件套,逻辑一交叉,代码就像毛线团,谁都不敢动。

写到这里,你是不是已经开始“恐惧”,迫切想知道怎么优雅解决?

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 官方文档