Photo by Joan Gamell on Unsplash
React useState Functional Updates and Why They're Important
Make sure your state is never stale by using a functional update
One of the ways to manage state in React is with the useState
hook.
It's a function that returns a value (the state) and a function to update the value.
Let's take a look at how that works.
React useState: Basic Update
function MyComponent() {
const [count, setCount] = useState(0);
const onClick = () => setCount(count + 1);
return <button onClick={onClick}>{count}</button>;
}
In the example above, the state we're managing is a counter. The button displays the current value of the count
and clicking on that button increments the count by 1.
Easy enough.
But there's a subtle problem with the example above.
When the button is clicked and we update the count
, it depends on the current value of count. Intuitively this makes sense, but the problem has to do with closures. The value count
in setCount(count + 1)
is defined during the render cycle of the component.
In other words, count
is a fixed value.
We could replace the above with setCount(0 + 1)
(count = 0
) and it wouldn't change things. This means that if I were to call onClick
multiple times, the value for count
would be the same for every call. If I spam the button multiple times, I'm basically just doing this over and over again: setCount(0 + 1)
.
React provides a way to get around this by using a functional update when we call setState
(setCount
in this case).
Here's how it works.
React useState: Functional Update
function MyComponent() {
const [count, setCount] = useState(0);
const onClick = () => setCount(prevCount => prevCount + 1);
return <button onClick={onClick}>{count}</button>;
}
The difference in this example is that when we call setCount
, we pass it a function. When you pass a function to a state updater, React will guarantee that the function is called with the most recent state. If I were to call onClick
multiple times this time, React would call the functional updater at some later point and make sure the correct count
is used.
The difference is that React is guaranteed to use the latest version of the state when it calls the function.
Demo
Here's an example of the above two use cases. The bad way uses the basic update syntax and the good way uses the functional update syntax.
Try spamming the buttons and see what happens.