3

I am just learning React and I was doing the tutorial : https://reactjs.org/tutorial/tutorial.html

In it, we are suppose to create a function that calculate the winner of the tic-tac-toe and we pass to it the list of the squares' contents. I update this list each time a square is clicked. However, I noticed that when I use this.setState to set the squares list of my Board object and then try to have it with this.state.squares I do not get the active state but the previous one.

Like if I add an X in the first square, it will be in this.state.squares at the next move.

Here is the code, I use :

handleClick(square){
    let squares = this.state.squares.slice();
    squares[square] = this.state.playing;
    console.log(squares);
    this.setState({squares: squares});
    if(this.state.playing == 'X'){
      this.state.playing = 'O';
    }
    else{
      this.state.playing = 'X';
    }    
    this.state.winner = calculateWinner(this.state.squares); #If I do that I get the previous state
    this.state.winner = calculateWinner(squares); #If I do that I get the current state 
  }

Why does it do that ?

Soudini
  • 65
  • 1
  • 5
  • `setState` is async. – Andrew Li Dec 23 '18 at 19:06
  • Possible duplicate of [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – JJJ Dec 23 '18 at 19:32

3 Answers3

2

According to the docs:

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

setState is an asynchronous method which effectively means that all other code in your handleClick function will execute before this.state.squares is mutated.

But there's another issue in your code too -- you're also trying to modify state directly:

if(this.state.playing == 'X'){
  this.state.playing = 'O';
}
else{
  this.state.playing = 'X';

Modifying this.state directly will not re-render your component.

To resolve these issues, you may use a setState callback:

this.setState({squares: squares}, () => {

    if(this.state.playing == 'X'){
      this.setState({"playing":"O"});
    }
    else{
      this.setState({"playing":"X"});
    }
    // I'm assuming that `calculateWinner` does not depend on this.state.playing   
    this.setState({"winner":calculateWinner(this.state.squares));
});

The setState callback is only invoked once the this.state.squares mutation has occurred -- ensuring that this.state.squares is updated before you invoke calculateWinner.

Elliot B.
  • 17,060
  • 10
  • 80
  • 101
0

setState is asynchronous but it can take a callback:

this.setState(
  { squares: squares },
  () => console.log("whatever")
);
0x6C38
  • 6,796
  • 4
  • 35
  • 47
0

Heres a quick walkthrough of the different methods of the

LifeCycle

of a component. You must have good understanding of the lifecylce methods to code in react. It will tell you "

When does state update in React

"

Methods in Mounting Phase:

It begins when an instance of a component is created and when it gets rendered into the DOM.

1.constructor(props) - it is called when the component is first initialized. This method is only called once. 2.componentWillMount() - it is called when a component is about to mount. 3.render() -it is called when a component is rendered. 4.componentDidMount() - it is called when a component has finished mounting.

Methods in Updating Phase:

It begins when a component's properties or state changes.

1.componentWillReceiveProps(nextProps) - it is called when a component has updated and is receiving new props. 2.shouldComponentUpdate(nextProps, nextState) -it is called after receiving props and is about to update. If this method returns false, componentWillUpdate(), render(), and componentDidUpdate() will not execute. 3.componentWillUpdate(nextProps, nextState) -it is called when a component is about to be updated. 4.render() - called when a component is rerendered. 5.componentDidUpdate(prevProps, prevState) -it is called when a component has finished updating.

Methods in Unmounting Phase:

It begins when a component is being removed from the DOM.

1.componentWillUnmount() - it iscalled immediately before a component unmounts.

Aftab22
  • 550
  • 6
  • 8