1
votes

I am trying to adapt the tic-tac-toe React tutorial and create a simple bingo game (with the ability to change the board size). I have the following component hierarchy:

App -> Game -> Board -> Square

The OnClick function gets passed down from the Game to the Square via props. Once I have calculated that the user has Bingo, I pop up a Dialog with a button allowing them to refresh the game (render new items in each square and reset the "hasBingo" state). For this I am using a consistent function (refreshBoard) which also runs when the board is first rendered and when the rows prop is changes. When I click the button on the dialog, the board refreshes and looks ready for a new round, however the onClick event on the squares does not get fired anymore (it appears that the prop is still there in dev tools though).

If I change the rows prop by setting the state in App, the board re-renders and works fine. Is there something I am missing with the dialog? Could it still be rendered on top of the board and "hijacking" the clicks, even though it's not visible?

Stack Blitz here: https://react-jdfqfo.stackblitz.io

  class Game extends React.Component {

  constructor(props) {
    super(props);
    let numSquares = this.props.rows * this.props.rows;
    this.state = ( {
      numSquares : numSquares,
      squares : Array(numSquares).fill(false),
      phrases: Array(numSquares).fill(false),
      hasBingo: false,
      rows: this.props.rows,
    });
  }

  refreshBoard(rows) {
    //Reset the board
    let numSquares = rows * rows;
    this.setState({hasBingo:false,
     rows: rows,
     squares: Array(rows * rows).fill(false),
     phrases: Array(rows * rows).fill(false) })

    //Get new items from API to show on the board
    fetch('http://xxx')
        .then(res => res.json())
        .then((data) => {
          this.setState({ phrases: data.map(( {text}) => text) })
        })

  }

  componentDidMount() {
        this.refreshBoard(this.state.rows);
  }

      componentWillReceiveProps(nextProps) {
        //The App component state could change the number of rows, listen for that event
        this.setState({ rows: nextProps.rows });  
        this.refreshBoard(nextProps.rows);
      }



  handleClick(i) {
    const squares = this.state.squares.slice();
     if (this.state.hasBingo) {
       return;
     }
    squares[i] = !squares[i];
    this.setState({
        squares: squares,
      });
  }


   calculateBingo(squares, rows) {
   //Returns true for bingo, or null. Code removed for brevity


  return null;
}

  render() {

    let squares = this.state.squares;
    let winner = this.calculateBingo(squares, this.state.rows);
    let phrases = this.state.phrases;


    let Transition = React.forwardRef(function Transition(props, ref) {
      return <Slide direction="up" ref={ref} {...props} />;
    });


    let status;
    if (winner) {
      this.state.hasBingo = true;
    }

    return (
      <div className="game">
        <div className="game-board">

          <Board 
            squares={squares}
            phrases={phrases}
            rows={this.state.rows}
            onClick={(i) => this.handleClick(i)}/>
         </div>

        <div className="game-info">
          <Dialog
            open={this.state.hasBingo}
            TransitionComponent={Transition}
            keepMounted
            aria-labelledby="alert-dialog-slide-title"
            aria-describedby="alert-dialog-slide-description"
          >
        <DialogTitle id="alert-dialog-slide-title">{"BINGO"}</DialogTitle>
        <DialogContent>
          <DialogContentText id="alert-dialog-slide-description">
            Well done!
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => this.refreshBoard(this.state.rows)} color="primary">
            Start New Game
          </Button>
        </DialogActions>
      </Dialog>
        </div>

      </div>
    );
  }
}


export default Game;

1
stackblitz.com/fork/react make a stackblitz , otherwise it would be almost impossible to come with a solution with this error that works once and once notRenaldo Balaj
Stack Blitz available here react-jdfqfo.stackblitz.ioalex_6169
done check my answerRenaldo Balaj

1 Answers

0
votes

Like I promised I delivered: https://stackblitz.com/edit/react-jdfqfo (took about 30min but it was intresting)

The problem was on

<Dialog
            open={this.state.hasBingo}
            TransitionComponent={Transition}
>

-You have a transition that goes up, but it always stays there even when open is false (when the state changes), I removed it and works fine, but you can add a handler for that transition and by using Dialog onClose so you can remove it when open is false.

-I made you a few fixes, on the render you were updating the state, you should not(try to check react warmings on the console). I added that logic at handleClick :)