Simple example: i want to choose one card from the deck and take it to my hand. When i choose the card, i append it to state "chosenCard". So, when i chose the card, i want to do next thing:
setMyCards(prevState => [...prevState, {...chosenCard}])
setChosenCard(null)
The question is: is it okay? Changing state is asyncronous, so is it accurate, that first function will work properly before second one? And if yes, why? Is it possible, that second function can change the state and first function will work incorrect (maybe in more complicated case)?
If I understand you correctly, you are worried that the second line of code could take effect before the first one, effectively adding a null
value to myCards
.
You can safely assume, that this will not happen. When setMyCards
is executed, chosenCard
will not be reset to null
yet. Reading the value of chosenCard
in the first line is not asynchronous, so anything that happens later in the code will not have any effect.
You could have a different situation if you had the opposite execution order:
setChosenCard({ newValue: 42 })
setMyCards(prevState => [...prevState, {...chosenCard}])
In this case, the new value of chosenCard
would become visible in the next render cycle only and setMyCards
would not pick it up yet.
There are different ways to deal with this:
don't immediately read a state variable after setting its value
const newValue = { newValue: 42 }
setChosenCard(newValue)
setMyCards(prevState => [...prevState, newValue])
use useReducer
if your application often modifies several state variables that have mutual dependencies, it could be better to use useReducer
instead of useState
. It would allow you to define a single action, which if dispatched, simultaneously updates chosenCard
and myCards
in the application state
manage state dependencies with useEffect
useEffect(
()=> chosenCard !== null && setMyCards(prevState => [...prevState, {...chosenCard}]),
[chosenCard]
)
This will ensure that setMyCards
is called only after the state change have taken effect. It is however discouraged to excessively use useEffect because it will make it hard to reason about implicit state changes: you-might-not-need-an-effect