DEV Community

Cover image for useState bugs part I: Unexpected state update.
Mwenedata Apotre
Mwenedata Apotre

Posted on

useState bugs part I: Unexpected state update.

So has it happened to you when the state updates in an unexpected way? Keep this question in mind.

One of the most discouraging things in a developer's life is when he's just starting his project and boom! a bug steps in and here is what goes on in his mind:

"Oooh I think this is just a small bug and I will just fix it and continue my project and I'll be fine".

So, next thing he does , he tries and tries to fix the bug until he can't and he immediately looses motivation to work on that project and his day becomes a loss.

In this useState bugs series part I let's talk about the most common issue with useState and how to fix it.

So has it happened to you when the state updates in an unexpected way? comes again the question. If yes it's because many reactjs developers use useState without understanding how it works under the hood. Let's take this small app example:
Image description

This is a very simple app we're going to be using for demonstration and what it does is just updating the state and the data in the h1 once I click on the increase button and also do so after 2 seconds when I click on the increase asynchronously button.

When I click on increase:
Image description

When I click on increase asynchronously , we wait two seconds and then see this:
Image description

So the buttons basically do the same thing within different time intervals.

So what I want to demonstrate here is the problem that may occur :

First note that the setTimeout function I used was to just simulate an asynchronous action like an http request where the state updates after it has resolved.

The problem occurs when I click once first on the increase asynchronously button and then click on the increase button imediately after more than once like maybe twice or thrice

What do you think will happen? So here's what happens:
I click on the asynchronous button:

async button clicked

Of course nothing happens unless 2 seconds have passed by

BUT:during that 2 seconds period I also click on the increase button exactly three times:
3 times

And once 2 seconds are over here's the result :
2 seconds over

But why? We already had 3 as the value but the value changed back to 1, unexpected right?

So here is an explanation: When you click on the increase asynchronously and the javascript reaches the 'setNumber(number +1)' line it stores the current value and after two seconds are over it will add one to the stored value and in the example above the number was O so it added 1 and the result was 1.

This may produce unexpected behavior and may frustrate many developers once they don't recognize where the problem is.

So how to solve that :

Solution: Use updating using a callback function in useState hook.

Here's how:

solution

const increaseAsynchronously = () => {
    setTimeout(() => {
      setNumber(prevNumber => setNumber(prevNumber + 1));
    },2000)
  }
Enter fullscreen mode Exit fullscreen mode

We provided the callback function and it takes one parameter which represents the current value of the state and that's why in that case it works perfectly fine . Let's repeat what we did before:

I click on the asynchronous button:

sync button clicked
Of course nothing happens unless 2 seconds have passed by

BUT:during that 2 seconds period I also click on the increase button exactly three times:
after 2 seconds

And once 2 seconds are over here's the result :
bug fixed

So it works , you can see that now the result is the expected one.

Thank you! Hope this helps someone.

Let's discuss about this post in the discussion section and like for the algorithm.

Top comments (0)