I’ve asked a similar question recently, but the situation was rather esoteric, so I’m rephrasing with a simpler example that demonstrates the problem. The rules of the game are simple, when either red or blue scores a goal, the totalScore
is adjusted by the current pointsPerGoal
. Before the totalScore
is updated, however, the pointsPerGoal
is adjusted by plus or minus one points for blue and red respectivley:
import React, {useState} from 'react';
export function App(props) {
const [totalScore, setTotalScore] = useState(0);
const [pointsPerGoal, setPointsPerGoal] = useState(3);
const handleRedGoal = () => {
setPointsPerGoal((pointsPerGoal) => pointsPerGoal - 1);
setTotalScore((totalScore) => totalScore + pointsPerGoal);
}
const handleBlueGoal = () => {
setPointsPerGoal((pointsPerGoal) => pointsPerGoal + 1);
setTotalScore((totalScore) => totalScore + pointsPerGoal)
}
// in another file, somewhere deep in the code base
const complexAction = () => {
handleRedGoal();
handleBlueGoal();
handleRedGoal();
// etc...
}
return (
<div className='App'>
<h1>{totalScore}</h1>
<button
onClick={()=>complexAction()}
>
Perform Complex Action
</button>
</div>
);
}
Due to the nature of react state updates, clicking the complex action button does not work; given the initial states, the outputted total score should be 7 but is instead 9, as each setTotalScore
call is operating on the initial pointsPerGoal
value.
Changing the handle goal methods results in the correct behavior:
const handleRedGoal = () => {
setPointsPerGoal((pointsPerGoal) => {
const newPointsPerGoal = pointsPerGoal - 1;
setTotalScore((totalScore) => totalScore + newPointsPerGoal);
return newPointsPerGoal;
});
};
const handleBlueGoal = () => {
setPointsPerGoal((pointsPerGoal) => {
const newPointsPerGoal = pointsPerGoal + 1;
setTotalScore((totalScore) => totalScore + newPointsPerGoal);
return newPointsPerGoal;
});
};
However, using the setState methods as a getters for relevant state data, and then nesting asynchronous setter function calls feels hacky. While the code is readable in this relatively simple example, large scale interdependent data updates could get hellish using this methodology, and I’m uncertain based on the react documentation as to whether this method will perform nested setState calls linearly or alternating. Any advice would be greatly appreciated!
Gryphon Patlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.