简体   繁体   中英

Render child component on parent state change

Full React code.

  class Square extends React.Component{
    render(){
      const letters = this.props.print;
      const print = letters === 0 ? "" : letters;

      return(
        <div>
          <button className='boxes' onClick={this.props.onClick}>
            {print}
          </button>
        </div>        
      );
    }   
  }


  class Game extends React.Component{
    constructor(props){
      super(props);
      this.handleClick = this.handleClick.bind(this);
      this.state = {
        letter: 'O',
        gameWon: false,
        letterArr: [0,0,0,0,0,0,0,0,0],
        winArr: [
         'X,X,X,0,0,0,0,0,0',
         '0,0,0,X,X,X,0,0,0',
         '0,0,0,0,0,0,X,X,X',
         'X,0,0,X,0,0,X,0,0',
         '0,X,0,0,X,0,0,X,0',
         '0,0,X,0,0,X,0,0,X',
         'X,0,0,0,X,0,0,0,X',
         '0,0,X,0,X,0,X,0,0',
         'O,O,O,0,0,0,0,0,0',
         '0,0,0,O,O,O,0,0,0',
         '0,0,0,0,0,0,O,O,O',
         'O,0,0,O,0,0,O,0,0',
         '0,O,0,0,O,0,0,O,0',
         '0,0,O,0,0,O,0,0,O',
         'O,0,0,0,O,0,0,0,O',
         '0,0,O,0,O,0,O,0,0'
        ]
      };
    }
    componentDidUpdate(){
      let o_s = this.state.letterArr.map((o) => {return o == 'X' ? 0 : o}).toString();
      let x_x = this.state.letterArr.map((x) => {return x == 'O' ? 0 : x}).toString();
      let oWin = (this.state.winArr.indexOf(o_s) != -1);
      let xWin = (this.state.winArr.indexOf(x_x) != -1);
      if( oWin == true ){
        console.log("O WINS!!!");
        board(gameVar.mode, gameVar.letter);
      }else if( xWin == true ){
        console.log("X WINS!!!");
        board(gameVar.mode, gameVar.letter);
      }
    }

    handleClick(i){
      let letter = this.state.letter;
      let arr = this.state.letterArr.slice();
      let change = this.state.letter == "O" ? "X" : "O";
      arr[i] = letter;
      this.setState({letter: change});
      this.setState({letterArr: arr});
    }

    squares(i){
      if(this.state.letterArr[i] == 0){
        return(
          <Square 
            print={this.state.letterArr[i]} 
            onClick={() => {this.handleClick(i)}} 
          />
        );
      }else{
        return(
          <Square
            print={this.state.letterArr[i]}
          />
        );
      }
    }

    render(){
      return(
        <div className='justify'>
          {this.squares(0)}
          {this.squares(1)}
          {this.squares(2)}
          {this.squares(3)}
          {this.squares(4)}
          {this.squares(5)}
          {this.squares(6)}
          {this.squares(7)}
          {this.squares(8)}
        </div>
      );
    }
  }

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

My issue is handleClick updates the constructor and then componentDidUpdate fires, calling Board() . I was expecting setState inside handleClick to re-render my class Box first.

  1. Why is setState not calling render?
  2. How can I call board() after Box updates with new props?

Link to full code: https://codepen.io/xcidis/pen/qVPoME?editors=0011

There are a number of problems with your code. In the render method on your Game component you are calling the method Box() , but that method does not return any value. Even if it did you would need to make some changes since I assume you want multiple boxes to render. Also the Box() method on your Game component doesn't take any value as an argument, but you are calling it with a number.

In your Box component you are extracting the const num from the property print , but print is not passed to the component from the Game component.

There are a bunch of other problems as well... I suppose this isn't the complete code so didn't bother writing up all the issues.

componentDidUpdate(){
      let o_s = this.state.letterArr.map((o) => {return o == 'X' ? 0 : o}).toString();
      let x_x = this.state.letterArr.map((x) => {return x == 'O' ? 0 : x}).toString();
      let oWin = (this.state.winArr.indexOf(o_s) != -1);
      let xWin = (this.state.winArr.indexOf(x_x) != -1);
      if( oWin == true ){
        //confetti();
        setTimeout(function(){
          alert('O WINN!!!')
          board(gameVar.mode, gameVar.letter)
        }, 3000);
      }else if( xWin == true ){
        //confetti();
        setTimeout(function(){
          alert('X WINS!!!')
          board(gameVar.mode, gameVar.letter)
        }, 3000);
      }
    }

Apparently setState and componentDidUpdate are asynchronous. I used setTimeout to pause setState -> componentDidUpdate firing before my component rendered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM