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

标签 javascript reactjs asynchronous setstate react-lifecycle

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

当应用程序安装时,我会生成一个随机板,其中填充了一些设置为“事件”的方 block ,而另一些则没有。我在 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
        })
      }
    }
  }

当用户单击按钮调整大小时,板成功更改尺寸,但它不会像应有的那样生成随机“事件”方 block 。它只是改变了棋盘的高度和宽度,但棋盘是空的。

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

很确定我想得太多了。

您可以查看 codesandbox 上的代码。

最佳答案

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

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

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

据我所知,每次用户更改大小时您都想要执行以下操作:

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

您只需要 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 生命周期方法中

关于javascript - React - 使用 componentDidUpdate 根据从另一个函数传递的数据更新状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52487585/

相关文章:

javascript - 如何使用forwardRef()进行循环依赖?

javascript - 无法读取 ReactJS 中未定义的属性 'state' (Gatsby)

python - 是什么阻止我的异步代码运行异步?

javascript - 您可以直接使用 .then 调用异步函数/方法吗?

javascript - 从预先存在的字段生成 ISO 日期

javascript - 无法将 php 中的 json 编码值解析为 javascript/jquery 中的 JSON 解析

Reactjs 更新状态中数组中的单个元素

c++ - 对运算符(operator) 'delete' 的调用是同步的吗?

javascript - 动态运行 jQuery 代码(如果我的主体添加 div 类)

javascript - 如何在reactjs中取消选中复选框时清空值?