React - 使用 componentDidUpdate 根据从另一个函数传递的数据更新状态

React - Using componentDidUpdate to update state based on data passed from another function

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

当应用程序安装时,我生成了一个随机板,其中填充了一些设置为 "alive" 的方块,有些则没有。我在里面处理这个 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 调整板的大小,我想更改板的大小,然后再次用随机 "alive" 单元格填充它。这里是 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 获取新的电路板尺寸并用该电路板尺寸的随机 "alive" 单元格填充它,就像我最初做的那样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
        })
      }
    }
  }

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

如何使用 componentDidUpdate 在调整大小时用随机 "alive" 单元格填充游戏板(类似于最初安装时的操作,但在板改变尺寸时适当调整大小) . componentDidUpdate 是正确的方法吗?这是 setState 异步的问题吗?

很确定我想多了。

您可以在 codesandbox 上查看代码。

您不需要为此使用 componentDidUpdate,稍后会详细介绍。

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

无论哪种方式,如果您仔细查看您的代码,就会发现您在不必要的情况下更新了太多次状态。如果您事先已经知道用户想要板子的尺寸,请一次完成。

据我了解,每次用户更改大小时您都希望执行以下操作:

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

您只需要 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
  });
};

Codesandbox example

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