0

我正在学习 React 并正在开发 John Conway 的 Game of Life 应用程序。我在状态/构造函数中定义了一个二维数组,它创建了一个正方形游戏板。我有一个名为的函数isSquareAlive,它处理网格中的特定方块在生命游戏的意义上是否“活着”,并更新方块并将它们设置为如果用户点击它们则它们是活着的。我还有另一个名为selectBoardSize的函数,它允许用户单击按钮并调整板的大小。

当应用程序安装时,我会生成一个随机板,其中填充了一些设置为“活动”的方块,而另一些则没有。我在里面处理这个componentDidMount

  componentDidMount = () => {
    const data = this.state.board;
    // Creates random decimal number between 0 and 1
    const startingBoard = data.map(a => a.map(Math.random));
    // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
    const rounded = startingBoard.map(a => a.map(Math.round));

    this.setState({
       board: rounded
    });
  }

这工作正常。如果用户尝试通过selectBoardSize我想更改板的大小来调整板的大小,然后再次用随机的“活动”单元格填充它。这里是selectBoardSize

  // Allows user to click button and change size of game board
  selectBoardSize = (width, height) => {
    this.setState({
      boardHeight: height,
      boardWidth: width,
      board: Array(this.state.boardHeight).fill(0).map(_ =>
              Array(this.state.boardWidth).fill(0))
    });
      {/*this.onChangeBoardSize(width, height);*/}
  }

当用户更改电路板尺寸时,我试图用来componentDidUpdate获取新的电路板尺寸并用该电路板尺寸的随机“活动”单元格填充它,就像我最初使用componentDidMount. 这是我遇到困难的地方。

这是我的componentDidUpdate

  // Attempts to fill board with random alive squares when user resizes the size of the board via onClick/selectBoardSize()
  componentDidUpdate = (prevProps, prevState) => {
    console.log('PrevState is : ' + prevProps, prevState);

    // Attempts to update board height and width and then populate board with random "alive" squares
    if(this.state.boardWidth !== prevState.boardWidth) {
      if(this.state.boardHeight !== prevState.boardHeight) {
        // Console.log runs, if statements equate to true when user resizes board
        console.log('Nested if statements in componentDidUpdate triggered');

        const boardWidth = this.state.boardWidth;
        const boardHeight = this.state.boardHeight;
        const data = this.state.board;
        // Creates random decimal number between 0 and 1
        const startingBoard = data.map(a => a.map(Math.random));
        // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
        const rounded = startingBoard.map(a => a.map(Math.round));

        this.setState({
          boardWidth: boardWidth,
          boardHeight: boardHeight,
          board: rounded
        })
      }
    }
  }

当用户单击按钮来调整它的大小时,板成功地改变了尺寸,但它不会像它应该那样生成随机的“活动”方块。它只是改变了板的高度和宽度,但板是空的。

调整大小时如何使用componentDidUpdate随机“活动”单元填充游戏板(类似于最初安装时的操作,但在板改变大小时调整大小)。是componentDidUpdate正确的方法吗?这是 setState 异步的问题吗?

很确定我想多了。

您可以在codesandbox上查看代码。

4

1 回答 1

2

你不需要使用componentDidUpdate它,但稍后会更多。

这不起作用,因为您(顺便说一句,正确地)将您的componentDidMount代码包装成两个条件,以检查boardWidthAND是否boardHeight发生了变化。问题是,高度永远不会改变,所以它永远不会到达代码的那部分。

无论哪种方式,如果您仔细查看您的代码,您会在不需要的情况下多次更新状态。如果您事先已经知道用户希望电路板的尺寸,请一次性完成。

这是我理解每次用户更改大小时您想要做的事情:

  • 根据所需的宽度和高度创建一个新板;
  • 用随机的活方块填充它;

您只需要该onChangeBoardSize功能,只需稍作更改。请注意,您不需要从状态中检索板,因为它会因旧的宽度和高度而过时;

onChangeBoardSize = (width, height) => {
  // Recreate board with new width and height values
  const data = Array(height)
    .fill(0)
    .map(_ => Array(width).fill(0));
  // Creates random decimal number between 0 and 1
  const startingBoard = data.map(a => a.map(Math.random));
  // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
  const rounded = startingBoard.map(a => a.map(Math.round));

  this.setState({
    boardHeight: height,
    boardWidth: width,
    board: rounded
  });
};

代码沙盒示例

提示:注意过多的子顺序状态修改。总是更喜欢一次完成所有操作,而不是按顺序触发 setState。特别是在反应生命周期方法中

于 2018-09-24T22:35:47.413 回答