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
2 Answers
Reset to default 5Instead 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.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745509408a4630701.html
评论列表(0条)