In this code in react.js a button click change the state, but the execution of setState seems to be synchronous
https://codesandbox.io/s/setstate-synchronous-9sctlp
import React from "react";
class App extends React.Component {
state = {
data: "start value"
};
do = () => {
console.log("before setState: " + this.state.data);
this.setState({ data: "new value" });
console.log("after setState: " + this.state.data);
};
asyncro = async () => {
let promise = new Promise((resolve) => {
setTimeout(resolve, 1000);
});
return promise;
};
render() {
return (
<div className="App">
<button
onClick={async () => {
await this.asyncro();
this.do();
}}
>
click
</button>
</div>
);
}
}
export default App;
Why the output is?
before setState: start value
after setState: new value
And if I delete
await this.asyncro();
the output is the expected result because setState is not syncronous
before setState: start value
after setState: start value
2
Answers
Finally I found the answer thanks to Dan Abramov
https://twitter.com/dan_abramov/status/949992957180104704
Then because setState is inside of a async/await block with something to call in the future then setState is synchronous
IMPORTANT: that behavior has changed in react version 18 and this behavior do not happen any more.
https://react.dev/blog/2022/03/29/react-v18#new-feature-automatic-batching
When you use functional components (and hooks) as recommended by the react team, you get the expected result and ONLY the expected result.
One of the reasons the community has made the switch to functional components instead of class components is that class components have a tendency to behave unpredictably and can have non-obvious interactions with function scope and state, as evident by your question.
Here is your example rewritten as a functional component, notice it behaves as expected: