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>
);
}
- 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>
);
}
- 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
My other Blogs
Oldest comments (26)
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...
Yeah! absolutely correct... and that's why I use two diffrent states
my scenario was
and I was not getting the updated state. as you can see in the example
and two solve the I use useEffect.
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.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...
Yeah! I will definitely try it...
I modified your code to make it work in the expected way:
codesandbox.io/s/red-field-isi29y?...
This is really good
Hey man, thanks for the info.
Thanks! It was really helpful
So recently I learnt this the hard way too. But what I realized is if you await setCount call, although it doesnot return a promise, the following code will execute after the count has incremented. Hope it helps :)
Thanks for the info. I would love to read the hard way. It might help many of us.
I came to the same solution, I I think this is why: developer.mozilla.org/en-US/docs/W...
Muchas gracias, fue muy util.
Thank you very much, it was very useful.
Thanks for the writeup. Recently had to complete a project and ran into this issue. Now I at least know how to resolve it in future cases. ๐
๐
Can I use async/ await too?
tbh
I don't know exactly may be you can or can't.
I would prefer not to use it.
Another (bit-tricky) way to solve this problem, is by setting the 'count' state with a callback, which returns an IIFE by itself, that will take the result of 'count' incremental as argument, sets doubleCount, and returns back the argument, which is the finally returned value for setCound.
Another approach:- codesandbox.io/s/muddy-brook-iyzwk...
Thanks for this article.
But I wanna add here useState is not async. It is actually sync.
why it doesn't update immediately because of the closure.
more on this here: youtube.com/watch?v=RAJD4KpX8LA
thanks :)
PS: i'm still learning it how it does work and how react render works under the hood.
Thanks for the input.
Shareef Bacha