React's state update is async and that's why you should not try to use the state (like logging or any other reading operation) just after setting it. But only async keyword seems to not give the total picture of how React updates the state.
How is this state update different from a ref update done asynchronously ?
Consider the following snippet where we simulate async updation of statefulRef. Even after we update the statefulRef asynchronously, if we access it after the update, we will get the latest value. But the same is not true with state. I know that both render and closure take part in explaining this state update but I would like to have a detailed answer explaining the differences of async behavior that we see below :-
const {
useState,
useRef
} = React
function App() {
const [state, setState] = useState({current:0});
const statefulRef = useRef(0);
function updateState() {
// below is async operation
setState({current:state.current + 1});
// below is async logging
setTimeout(() => console.log("React state : ",state.current), 500);
}
function updateRef() {
// below is async operation
setTimeout(() => statefulRef.current += 1, 200);
// below is async logging
setTimeout(() => console.log("React ref : ",statefulRef.current), 500);
}
return (
<div >
<button onClick = {updateState}> Update State </button>
<button onClick = {updateRef}> Update Ref </button>
</div>
)
}
ReactDOM.render( < App / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>