DEV Community

loading...

React useState hook is asynchronous!

Mohammed Nadeem Shareef
Hello. I am a FrontEnd Developer I work with reactJS, nextJS, TypeScript, firebase, tailwindcss, SCSS.
・2 min read

Hello Developers 👋

I would like to share something I recently got to know, so the background is, in my project I was using useState value right after updating it and I was getting previous value(not updated value) and to my surprise I found out that useState hook is asynchronous

what it is?

Basically, the thing is you don't get update value right after updating state.

What is the work around/solution?

We can use the useEffect hook and add our state in the dependence array, and we will always get the updated value.

Show me the code 🤩🤩🤩

import { useState } from "react";

export default function CountWithoutEffect() {
    const [count, setCount] = useState(0);
    const [doubleCount, setDoubleCount] = useState(count * 2);
    const handleCount = () => {
        setCount(count + 1);
        setDoubleCount(count * 2); // This will not use the latest value of count
    };
    return (
        <div className="App">
            <div>
                <h2>Count Without useEffect</h2>
                <h3>Count: {count}</h3>
                <h3>Count * 2: {doubleCount}</h3>
                <button onClick={handleCount}>Count++</button>
            </div>
        </div>
    );
}

Enter fullscreen mode Exit fullscreen mode
  • Here we have very simple and stright forward component.
  • On button click we are updating two states and one state is dependent on other state.
  • The doubleCount will be one step behind count.
  • Check out the Live Demo

Solving this issue 🧐🧐🧐

This can be easily solve with useEffect hook, let's see the code


import { useState, useEffect } from "react";

export default function CountWithEffect() {
    const [count, setCount] = useState(0);
    const [doubleCount, setDoubleCount] = useState(count * 2);
    const handleCount = () => {
        setCount(count + 1);
    };

    useEffect(() => {
        setDoubleCount(count * 2); // This will always use latest value of count
    }, [count]);

    return (
        <div>
            <h2>Count with useEffect</h2>
            <h3>Count: {count}</h3>
            <h3>Count * 2: {doubleCount}</h3>
            <button onClick={handleCount}>Count++</button>
        </div>
    );
}

Enter fullscreen mode Exit fullscreen mode
  • Here, when ever count changes we are updating doubleCount
  • Check out the live Demo

Closing here 👋👋👋

This is Shareef.
Live demo
GitHub repo of this blog
Stackover flow link for more info
My Portfolio
Twitter ShareefBhai99
Linkedin
My other Blogs

Discussion (4)

Collapse
noyan profile image
noyan • Edited

The doubleCount will be one step behind, because state is just a normal number in each call.
So, if you call setCount (count*2) after setCount(count+1), Counter displays 0 every time.
livedemo: codesandbox.io/s/vigorous-antonell...
see: overreacted.io/a-complete-guide-to...

Collapse
shareef profile image
Mohammed Nadeem Shareef Author • Edited

Yeah! absolutely correct... and that's why I use two diffrent states

my scenario was


setState(state); // Update some state
doSomething(); // Do something with the state

Enter fullscreen mode Exit fullscreen mode

and I was not getting the updated state. as you can see in the example
and two solve the I use useEffect.

setState(state); // Updates the state
useEffect(() => {
    doSomething(state) // do something with the updated state.
},[state]) // This will call again when the state is updated
Enter fullscreen mode Exit fullscreen mode
Collapse
noyan profile image
noyan

I realized my comment was already included in your post. Sorry about that.

Actually, there is a simple way to write it without useEffect: setState(prev => prev + 1). It will update properly even if you update it multiple times in one render.

const Func = () => {
  const [count, setCount] = useState(0);    // initially count = 0 (When it was first mounted)
  const handleClick = () => {
    setCount(prev => prev + 1);                 // count = 1 
    setCount(prev => prev + 1);                 // count = 2
  }

  return (
    <button onClick={handleClick}>{count}</button>
)
}
Enter fullscreen mode Exit fullscreen mode

It is called functional update. This one is easier to use or understand, and I recommend to use it when needed.
reactjs.org/docs/hooks-reference.h...

Thread Thread
shareef profile image
Mohammed Nadeem Shareef Author

Yeah! I will definitely try it...