I’m setting state in my app and referencing it. Why don’t I see the new values?
Fortunately, if you’ve run into a similar issue, there’s a simple solution and an important lesson about React state to learn along the way.
The main takeaway: Setting React state is an asynchronous process.
To better understand, let’s look at the following component:
All that’s happening here is two names of colors being displayed. There’s a button below that — when clicked — updates the state of color1
and then calls the listNewColors()
function. All this function does is print a message containing the values of color1
and color2
.
At first it might seem logical for the code to step through as follows
handleColor1Change()
function is calledcolor1
is changed to “Green”.listNewColors()
is called and sets the value ofmessage
to display the newcolor1
value.
After all, the value of color1
is updated prior to listNewColors()
, right? Not quite. Because React setState is an asynchronous process in which setState
becomes a queued item in the callstack, the entirety of handleColorChange()
is completed before re-rendering the DOM. As a result, message
will print with the old value of color1
before the DOM re-renders with the updated value.
So how do we get around this? The short answer is to use a callback function for actions to be triggered only after your state has updated. There are a few ways to do this, but my preference is the useEffect
hook.
Here, the call to listNewColors()
no longer exists inside of handleColorChange()
. Instead it is triggered by the useEffect
hook whose dependency is color1
. This means that until the state of color1
changes, only then do we set the state of message
with the actual updated values.
The moral of the story is that setting and reading the same state within a function can quickly present issues.