Lesson 6. Get the current state when dealing with async code 1. Update the state based on its current value
Have a look at this example:
Result
I expect to see a growing string, with a new dash - added each second. But
what I see is just one dash. It tells me that in the callback passed to
setInterval, I don’t get the latest value of string, but why?
The reason has less to do with React and hooks than with JavaScript closures. Remember that React components are functions, and updating a local state triggers a new rendering, therefore another call to this function.
- Rendering #1:
stringcontains>. We callsetIntervalso each second, we must updatestring. This rendering’s version ofstring. - Rendering #2 (triggered by the first call to
setString):stringcontains one dash:->.
Since we make the call to setInterval in the first rendering, the version of
string used is the first rendering version, not the next ones. React hooks
can’t do much to help us here; it’s how JavaScript closures work.
Not-working solution
Oh, that one is easy, you may say. You forgot to pass string in the
dependencies array, as the second argument of useEffect.
useEffect(() => {// ...}, [string])
If we pass string in the dependencies array, the problem is that setInterval
will be called each time the component is rerendered, meaning each time we call
setString. Not what we want to do.
Using the alternative syntax to update a state
We want to update a local state with a new value derived from the current value.
It is a perfect situation where the second syntax offered by setXXX (returned
by useState) will help us a lot!
setInterval(() => {setString((currentString) => '-' + currentString)}, 1000)
With this syntax, we don’t have to care about getting the latest value of
string in the callback we give to setInterval since we are sure that
currentString (the first parameter of the callback passed to setString) is
up to date.
Here is what this working solution looks like:
Result
This first solution works perfectly when you need to get the latest value to update the state. But what if you need it to trigger another side effect? Let’s see another way to get this latest value.