I'm new to React, going through the tutorial on the React website. In the step by step tutorial, there is a section which explains that you should not rely on the value of state for calculating the next state, because state updates are asynchronous. Instead, they explain, you should use a version of setState that accepts a function to which the previous state is passed as an argument.
However, in the practical tutorial, the following code appears:
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
in which the setState call passes an object that relies on a value from this.state. Why is this code ok and why would one not have to worry about asynchronous setState execution in this case? I'm trying to understand when exactly I can rely directly on the value of this.state in my React code.
Thanks in advance!
CodePudding user response:
The tutorial's explanation is wrong. There are many cases in which you can rely on referencing this.state
directly, including the case in the code snippet.
Referencing this.state
directly is a problem only if
- You have previously called
this.setState
with the component, and - The component hasn't rerendered yet, and
- You want to call
this.setState
again, while taking into account the value that was just set
If any of the above conditions are false, it's just fine to set the state by referencing this.state
without using the callback version.
For example, in the snippet in your question, I'd presume that handleClick
is a click handler, and no other click handlers run - a different state setter does not get called before you call this.setState({ squares ...
, so there's no problem.
It would be problematic if you called multiple handleClick
s in sequence, though. For example, if you had something like
handleMultipleClicks() {
for (let i = 0; i < 5; i ) {
handleClick(i);
}
}
The above would be a problem, because you're calling this.setState
multiple times before giving the component a chance to re-render; the this.state.squares
that gets referenced in the second (and further) iterations of the loop would not reflect the value passed to this.setState
in the first iteration of the loop.
One way to think of it is: this.state
will reference the state at the end of the last re-render. If you write your code with that in mind, you'll be able to reliably determine whether you need to use the callback version of the state setter or not.
CodePudding user response:
In your example, you are not using the state immediately after setState
hence it works as expected. Consider this example where you can get some unexpected results due to asynchronous state updates.
handleClick(i) {
console.log(this.state.value); // 1, can be any value
this.setState({
value: this.state.value 1
});
console.log(this.state.value); // This is still 1, or the prev value
}
Also, it seems like you are using Class
components so the tutorials might be very old. I would also suggest you learn functional components and hooks. It will make your life easier :)