Cameron
Cameron

Reputation: 135

React not showing updated state in child components

This is an adaptation of the React tutorial. My intent is to use the selection of one or two players to migrate towards an automatic selection of moves. At this stage for some reason the selection of squares is not being captured in the call to handleMove(i) with the this.setState({squares:this.state.squares, xIsNext: !this.state.xIsNext}) statement, as can be seen from the two console.log calls in both the Button and Square components.

This is the technique employed in the tutorial so I am not sure why the squares array is not updating. I read other postings and Facebook's discussion of immutability that states the function (in this case the handleMove(i), correct?) must complete before the change to state is reflected in the overall state. The calls to console.log in the other componets as well as the overall DOM do not reflect the clicks on the squares.

Can anyone tell me why this is not working? Thank you.

On JSBin

<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Tic Tac Toe</title>
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id='root'></div>
<script type='text/babel' >


function Square(props){
  console.log(props.value);
  return(
    <button className="square" onClick={() => props.onClick()}>{props.value}</button>    
    );
}



class Board extends React.Component{
  renderSquare(i){
    console.log(this.props.squares);  
    return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />
  }  

  render(){
    return(
    <div className="board">
    <div className="row">
        {this.renderSquare(0)}
        {this.renderSquare(1)}
        {this.renderSquare(2)}
    </div>
    <div className="row">
        {this.renderSquare(3)}
        {this.renderSquare(4)}
        {this.renderSquare(5)}
    </div>
    <div className="row">
        {this.renderSquare(6)}
        {this.renderSquare(7)}
        {this.renderSquare(8)}
    </div>
    </div>
    );
  }
}


class Game extends React.Component{

  constructor(props){
    super(props);
    this.state = {
      onePlayerGame: true,
      squares: Array(9).fill(null),
      xIsNext: true
    }
  }

  onePlayer(){
    this.setState({onePlayerGame: true});
    return(
    document.getElementById('onePlayer').style.color = "yellow",
    document.getElementById('twoPlayer').style.color = "black"
    );
  }


  twoPlayer(){
    this.setState({ onePlayerGame: false});
    return(
    document.getElementById('onePlayer').style.color= "black",
    document.getElementById('twoPlayer').style.color= "yellow"
    );

  }

  handleMove(i){
    const squares = this.state.squares.slice();
    squares[i] = this.state.xIsNext ? 'X':'O';


    this.setState({
      squares: this.state.squares,
      xIsNext: !this.state.xIsNext
    })
  }



  render(){
    return(
    <div id="main">
      <div>
       <button className="gameSelect" id="onePlayer" value={this.state.onePlayerGame} onClick={() => this.onePlayer()}  >One Player</button>
       <button className="gameSelect"  id="twoPlayer"value={this.state.onePlayerGame} onClick={() => this.twoPlayer()}  >Two Players</button>
      </div>

      <Board 
        squares={this.state.squares} 
        onClick={(i) => this.handleMove(i)} />

    </div>
    );
  }
}



ReactDOM.render(
  <Game />,
  document.getElementById('root')
)



</script>
</body>
</html>

Upvotes: 0

Views: 62

Answers (1)

QoP
QoP

Reputation: 28407

The selection is captured, but you are not saving the new value of squares in the state.

this

handleMove(i){
    const squares = this.state.squares.slice();
    squares[i] = this.state.xIsNext ? 'X':'O';


    this.setState({
      squares: this.state.squares, <----- You are not assigning the new value
      xIsNext: !this.state.xIsNext
    })
}

should be

handleMove(i){
    const squares = this.state.squares.slice();
    squares[i] = this.state.xIsNext ? 'X':'O';


    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext
    })
}

Here is the proper jsbin

Upvotes: 1

Related Questions