I found that, if:
- there are two
setState - the first one is called with a value obtained from
await - the both are called in the same thread
then, there is a frame where one state is set but the other is not.
Example:
const [bool1, setBool1] = useState(false)
const [bool2, setBool2] = useState(false)
useEffect(() => {
(async () => {
const _bool1 = await true
setBool1(_bool1)
const _bool2 = true
setBool2(_bool2)
})()
}, [])
console.log(`bool1: ${bool1}, bool2: ${bool2}`)
Live example (open browser console for output):
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
const {useState, useEffect} = React;
const App = () => {
const [bool1, setBool1] = useState(false)
const [bool2, setBool2] = useState(false)
useEffect(() => {
(async () => {
const _bool1 = await true;
setBool1(_bool1);
const _bool2 = true;
setBool2(_bool2);
})();
}, [])
console.log(`bool1: ${bool1}, bool2: ${bool2}`);
return <p>See browser console for output</p>;
}
ReactDOM.render(<App />, document.body);
</script>
The output is:
bool1: false, bool2: false
bool1: true, bool2: false
bool1: true, bool2: true
Here, the second line is confusing - I feel that there shouldn't be a frame where bool1 and bool2 don't have the same value. I know the fact that setState doesn't set a value in the same frame in general, but is that fact actually related in this case?
More confusingly, if 1. is not met, namely, if I remove await for setBool1, the second line vanishes. I don't get how the await breaks the synchronization between setBool1 and setBool2 in this case - because I think the promise is already reasolved when setBool1 is called, so it shouldn't make a difference.