You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React计算器开发异常:Reducer内调用setState致状态重复更新

问题根源与修复方案

问题根源

  1. 状态管理逻辑混乱:你把useState的更新函数(setWaitingForSecondNumber、setExpressionArray)传入了useReducer的reducer函数中,这完全违背了useReducer的设计初衷——reducer必须是纯函数,不能在内部执行外部状态更新这类副作用操作。同时混合useState和useReducer管理关联状态,极易造成状态不同步、重复更新的问题。
  2. 直接修改原状态:在"multiplication_operator"分支里,你直接对state数组执行push操作。React要求状态是不可变的,修改原状态会导致React无法正确识别状态变化,进而出现重复添加数值的异常。
  3. 状态职责拆分错误:本该由reducer统一管理的状态,你拆分到了外部的useState中,导致reducer无法完整掌控状态流转,触发不必要的渲染循环和状态冲突。

修复步骤

1. 统一状态到reducer中

把原本用useState管理的waitingForSecondNumber、expressionArray,以及当前输入值等所有和计算器逻辑相关的状态,全部整合到reducer的初始状态里:

const initialState = {
  currentValue: '0',
  expressionArray: [],
  waitingForSecondNumber: false
};

2. 改造reducer为纯函数

移除reducer里对外部setState的调用,所有状态更新都通过返回新的状态对象/数组实现,绝对不修改原状态:

function calculatorReducer(state, action) {
  switch (action.type) {
    case "multiplication_operator":
      if (state.waitingForSecondNumber) {
        // 创建新数组,避免修改原状态
        const newExpressionArray = [...state.expressionArray, state.currentValue];
        return {
          ...state,
          expressionArray: newExpressionArray,
          currentValue: '*',
          waitingForSecondNumber: false
        };
      } else {
        return {
          ...state,
          expressionArray: [state.currentValue, '*'],
          waitingForSecondNumber: true
        };
      }
    // 其他运算符、数字输入的case也按此方式,用扩展运算符创建新状态
    default:
      return state;
  }
}

3. 移除App组件中的冗余useState

App组件里不再单独声明waitingForSecondNumber和expressionArray的useState,直接从useReducer返回的状态中获取:

function App() {
  const [state, dispatch] = useReducer(calculatorReducer, initialState);

  return (
    <div className="calculator">
      <div className="expression-display">{state.expressionArray.join(' ')}</div>
      <div className="current-display">{state.currentValue}</div>
      <button onClick={() => dispatch({ type: "multiplication_operator" })}>×</button>
      {/* 其他按钮逻辑同理,替换为dispatch对应action */}
    </div>
  );
}

额外说明

不是Hook选择的问题,useReducer本身非常适合这种有复杂状态流转的计算器场景,问题出在你错误地混用了useState和useReducer,并且违反了React状态不可变、reducer必须是纯函数的核心规则。修复后所有状态逻辑都集中在reducer里,状态流转清晰,也不会再出现重复添加数值的问题。

内容的提问来源于stack exchange,提问作者superpav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:45:42