In a function inside a functional react component I may update multiple state variables. How can I ensure all state changes have taken place before running the next function.
Below, for example, imagine that calculateScore() is triggered on some event (perhaps some clicks in a game) and adds to the value of either a, b or both. I then wan’t to run determineWinner(). How can I run determineWinner() in a way which ensures both setA and setB have completed their asynchronous runs so that both a and b are up-to-date (after a single calculateScore() run)?
I didn’t find this in the docs or while searching around for a while here on stackOverflow.
Example
function MyComponent() {
let [a, setA] = useState(0);
let [b, setB] = useState(0);
let [winnerText, setWinnerText] = useState("")
function determineWinner() {
if (a > b) {
// Note, I don't want this to happen if the score ends up equal after both setA and setB from calculateScore() completes.
setWinnerText("A won!")
}
}
function calculateScore(aShouldIncrease, bShouldIncrease) {
if (aShouldIncrease) setA(prevA => prevA + 1);
if (bShouldIncrease) setB(prevB => prevB + 1);
determineWinner(); // Doesn't work to run it here, since setA and setB are asynchronous.
}
useEffect(() => {
determineWinner(); // Not guaranteed to work here, since perhaps only setA has completed so far and not setB? Right?
}, [a, b])
determineWinner(); // Even if we imagined I had some other condition to prevent it from being run prematurely, it may run when only a or only b has changed, right?
return <h1>{ winnerText }</h1>
}
I realize I could solve it by making all the calculations within the calculateScore without setting state, but I wonder if there is some point in react where I can be sure all setState() functions started from within a single function call will be completed.
2
Answers
Semantically it sounds like you want to perform an action when "the game score" is updated, not when any individual value therein is updated. So there’s a level of encapsulation not accounted for in the current code.
Keep the "game state" in one state object rather than two. For example, consider this:
Then updating that state would be a single "set" operation:
Then since only one state object was updated, you can trigger the effect with just that dependency: