TypeOfNaN

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!

clicking button with console log behind the 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.

If you'd like to support this blog by buying me a coffee I'd really appreciate it!

Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli