Why is the React useState Set Function Not Reflecting Changes Immediately?
Nick Scialli
May 02, 2021
One question that comes up a lot in React is why the changes made by state setting functions appear not to be reflected in our component immediately.
Example: A Simple Counter
If we use the example of a useState
hook that’s increments a counter, we can see this behavior:
import { useState } from 'react';
function MyCounter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
console.log(count);
}
return (
<div>
Count: {count}
<br />
<button onClick={increment}>Increment</button>
</div>
);
}
Loading this simple app, we can see that our console.log
is seemingly behind the actual count!
But this is actually exactly how it should work. Let’s dig into why.
State Setters are Asynchronous
It’s important to remember that state setters are asynchronous. When we call setCount
in our example, the increment
function code does not wait for count
to be updated. count
is being updated asynchronously, but it won’t be reflected until the next component render.
In fact, this is a good thing. We wouldn’t want the count
variable to be updated within the increment
function because that would blow away the concept of closures in JavaScript and closures are a very important and helpful concept in the language. Our increment
function has closure around the count
variable and we can be guaranteed during the execution of the increment
functiont that count
will be the same value throughout.
Conclusion
It’s important to remember that setting state is asynchronous and the new value of that stateful variable will be available to you during the next render, not immediately in the same function.
Nick Scialli is a senior UI engineer at Microsoft.