React Asynchronous useState Hook - Part 1

Published on
3 mins read
––– views

Why do we need it?

Let's create a simple counter button, which is the most common way to teach useState.

If you are on this page, I assume you know how to import and other basic setup.

function Counter() {
  // this will setup our counter, counter start's from 0
  const [counter, setCounter] = useState(0);

  return (
    <>
      // number of clicks will show here, {counter}
      <p>number of clicks: {counter}</p>
      <button
        onClick={() => {
          // after each click, we increment the counter
          setCounter(count + 1);
          console.log(counter);
          // what is the logged number after first click?
        }}
      >
        click to pet a cat
      </button>
    </>
  );
}

It is not what you think


The correct answer is 0, not 1 and I will explain why.

So, we start from zero, useState(0), and I'm telling you after the first click, the logged number will be 0, not 1. Makes no sense, I know.

The reason behind this weird behavior is that, setters, setCounter, does not update immediately. To get the updated value, we need to wait for the next render.

So, when we click on the button, counter is set to 0, and then 1. It's like following from a step behind. That is why the logged value is 0, not 1.

Updating the state value is that "long word", asynchronous. React will schedule an update, it won't be immediate, but it will get there on the next render. Like, you call the doctor's office and they tell you to visit tomorrow.

OK, cool story, can we fix that?

Yes we can.

Here is the same code, with few more lines.

function Counter() {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>number of clicks: {counter}</p>
      <button
        onClick={() => {
          // NEW LINE //
          const nextCounter = counter + 1;
          setCounter(nextCounter);

          // it will log 1
          console.log(counter);
        }}
      >
        click to pet a cat
      </button>
    </>
  );
}

Here we assigned the upcoming value in a variable, and called it inside setCounter(nextCounter)

In plain English


  1. Counter is 0,

  2. We declared nextCount is equal to current counter and + 1.

  3. When the button is clicked, setCounter is equal to nextCount, which is 1, not 0;

and that is pretty much it.

If you want to learn more, Here is the part 2