一步延迟更新导致 React State

Posted

技术标签:

【中文标题】一步延迟更新导致 React State【英文标题】:One step delay in updating result in React State 【发布时间】:2020-08-25 22:00:44 【问题描述】:

我有一个非常简单的计算器,它通过 React 计算两个输入,我在更新我的 state 中的 result 时遇到问题(将 result 状态更新为函数称为calc)。这是通过下一个动作完成的,而不是现在!

总而言之,现在结果状态计算出错误的值。

我的代码:

const App = () => 
  const [state, setState] = useState(
    firstVal: 0,
    secondVal: 0,
    operator: "+",
    result: 0
  );

  const  firstVal, secondVal, operator, result  = state;

  const calc = (firstVal, secondVal, operator) => 
    if (operator === "+") 
      return firstVal + secondVal;
     else if (operator === "-") 
      return firstVal - secondVal;
     else if (operator === "*") 
      return firstVal * secondVal;
     else if (operator === "/") 
      return firstVal / secondVal;
    
  ;

  const changeHandler = e => 
    setState(
      ...state,
      [e.target.name]:
        e.target.name === "operator" ? e.target.value : Number(e.target.value),
      result: calc(firstVal, secondVal, operator)
    );
  ;

  return (
    <div className="App">
      <input name="firstVal" onInput=changeHandler />

      <select name="operator" onChange=changeHandler>
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
      </select>

      <input name="secondVal" onInput=changeHandler />

      <p>result</p>
    </div>
  );
;

export default App;

我想我不了解 React 中的异步和状态。

这是我在codesandbox中的代码

【问题讨论】:

您能准确指出您的问题是什么吗?从您的描述中现在还不清楚。 您误解了状态的工作原理,看起来您正在尝试使用单个 changeHandler 函数来执行大约 4 个不同的任务。您根本不应该将结果存储在 state 中,因为结果是使用已经处于 state 中的值计算的。 我希望我的结果显示一个正确的值。 @TomOakley 你说你对状态一无所知。你可以read about state here,它会解释你哪里出错了。 @JMadelaine tnx,您的意思是每个处理程序都需要一个特定且单独的状态? 【参考方案1】:

不要将result 保存在您的状态中,只需在渲染时使用calc 方法计算结果即可。

  return (
    <div className="App">
      <input name="firstVal" onInput=changeHandler />

      <select name="operator" onChange=changeHandler>
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
      </select>

      <input name="secondVal" onInput=changeHandler />

      <p>calc(firstVal, secondVal, operator)</p>
    </div>
  );

我也不会使用状态对象 - 为每个状态变量使用不同的状态值和方法,例如:

import React,  useState  from "react";
import "./styles.css";

const App = () => 

  const [firstVal, setFirstVal] = useState(0)
  const [secondVal, setSecondVal] = useState(0)
  const [operator, setOperator] = useState('+')

  const calc = (firstVal, secondVal, operator) => 
    if (operator === "+") 
      return firstVal + secondVal;
     else if (operator === "-") 
      return firstVal - secondVal;
     else if (operator === "*") 
      return firstVal * secondVal;
     else if (operator === "/") 
      return firstVal / secondVal;
    
  ;

  return (
    <div className="App">
      <input name="firstVal" onInput=e => setFirstVal(Number(e.target.value)) />

      <select name="operator" onChange=e => setOperator(e.target.value)>
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
      </select>

      <input name="secondVal" onInput=e => setSecondVal(Number(e.target.value)) />

      <p>calc(firstVal, secondVal, operator)</p>
    </div>
  );
;

export default App;

这消除了changeHandler 方法的复杂混乱,并使代码更具可读性。

【讨论】:

【参考方案2】:

问题出在:

const changeHandler = e => 
    setState(
      ...state,
      [e.target.name]:
        e.target.name === "operator" ? e.target.value : Number(e.target.value),
      result: calc(firstVal, secondVal, operator)
    );
  ;

calc 被调用时,它仍然具有来自当前 状态的值,而不是通过onChange/onInput 处理程序设置的新值,因此观察到陈旧结果。

编辑:此答案试图解释观察到的行为发生的原因。至于如何解决,请看汤姆的回答。

【讨论】:

谢谢,我的解决方案是结合您的回答和汤姆的回答。

以上是关于一步延迟更新导致 React State的主要内容,如果未能解决你的问题,请参考以下文章

react setState

意外状态更新导致“useState”函数

React Hook更新state数组

使用新数组更新 React State

React生命周期, setState、props改变触发的钩子函数

React Reducer不会更新State