Considering simple state hook:
const [count, setCount] = React.useState(0);
I want to increase or decrease the count. Basically do the same thing shown in the hooks docs.
But as a known fact for the old this.setState
function:
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
and the right way to update the state based on the old state is:
this.setState((state) => ({
counter: state.counter + 1
}));
Does the same thing applies to setCount
?
Or I can be sure that count
is always up-to-date?
useState
hooks work differently than this.setState
. Calling your setter, setCount
in the below example, does work asynchronously, but since count
is not changed during the rendering of a functional component the evaluation is deterministic.
The following example, copied verbatim from Hooks at a Glance in the React docs, is 100% safe (you won't have any errors about calling methods on unmounted components) and will behave as expected:
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
The only time you would need to use the functional update where you pass a function to setCount
is if you need to call setCount
multiple times when referencing state. Note that this isn't because setState
is asynchronous—it's because count
is not updated until the next render.
For example, this would be a problem:
<button
onClick={() => {
setCount(count + 1)
setCount(count + 1) // since `count` is not dynamically updated mid-render, this evaluates to the same value as above
}}
/>
In practice, this pattern is relatively rare. You wouldn't call the setter multiple times in a single function in this way. Instead, if you are passing the setter as a prop on children, and those children reference the state controlled by the setter, then you would use the functional update pattern. Even in this scenario, though, React will re-render the component with each successive value.
As for concerns about whether this is a reliable and/or recommended approach, the React documentation has this to say about the matter (source):
You might hear a recommendation to always write code like
setCount(c => c + 1)
if the state you’re setting is calculated from the previous state. There is no harm in it, but it is also not always necessary.In most cases, there is no difference between these two approaches. React always makes sure that for intentional user actions, like clicks, the
count
state variable would be updated before the next click. This means there is no risk of a click handler seeing a “stale”count
at the beginning of the event handler.However, if you do multiple updates within the same event, updaters can be helpful. They’re also helpful if accessing the state variable itself is inconvenient (you might run into this when optimizing re-renders).
If you prefer consistency over slightly more verbose syntax, it’s reasonable to always write an updater if the state you’re setting is calculated from the previous state. If it’s calculated from the previous state of some other state variable, you might want to combine them into one object and use a reducer.
I am not sure the exact logic, and the use case of the count
state, but generally, you will need to call
setCount(count + 1);
Or, functional updates using callbacks
setCount(prev => prev + 1);
If you wish to update your state. However, do take note that the updating of state can be asynchronous, which is similar to the way class component's setState()
works. You may refer to the useState documentation for more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With