最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - One step delay in updating result in React State - Stack Overflow

programmeradmin0浏览0评论

I have a very simple calculator that calculates two inputs by React and I have a problem for updating result in my state (update result state by a function called calc). This is done with the next action and not in the moment!

In summary, now result state calculates a wrong value.

My Code:

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;

I think I don't understood something about asynchronous and state in React.

Here is my code in codesandbox

I have a very simple calculator that calculates two inputs by React and I have a problem for updating result in my state (update result state by a function called calc). This is done with the next action and not in the moment!

In summary, now result state calculates a wrong value.

My Code:

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;

I think I don't understood something about asynchronous and state in React.

Here is my code in codesandbox

Share Improve this question edited May 10, 2020 at 12:01 Amir asked May 10, 2020 at 11:49 AmirAmir 1,3583 gold badges15 silver badges29 bronze badges 5
  • can you highlight exactly what your problem is? It's unclear from your description right now. – Tom Oakley Commented May 10, 2020 at 11:54
  • You're misunderstanding how state works, and it looks like you're trying to use a single changeHandler function to do about 4 different tasks. You should not be storing the result in state at all because the result is calculated using values that are already in state. – JMadelaine Commented May 10, 2020 at 11:55
  • I want my result show a Correct value. @TomOakley – Amir Commented May 10, 2020 at 11:55
  • You said you don't know anything about state. You can read about state here which will explain where you are going wrong. – JMadelaine Commented May 10, 2020 at 11:59
  • @JMadelaine tnx, You mean each handler need a specific and separately state? – Amir Commented May 10, 2020 at 12:00
Add a ment  | 

2 Answers 2

Reset to default 5

Instead of holding result in your state, just calculate the result using the calc method at render time.

  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>
  );

I'd also not use a state object - use different state values and methods for each state variable, for example:

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;

This removes the plicated mess of the changeHandler method and makes the code far more readable.

The issue is in:

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

When calc is invoked, it still has the values from the current state, not the new value which has been set through the onChange/onInput handler, hence the observed stale results.

Edit: This answer tries to explain why the observed behavior happened. With regard to how to solve it, see Tom's answer.

发布评论

评论列表(0)

  1. 暂无评论