【问题标题】:Ensuring React state has updated for game loop确保游戏循环的 React 状态已更新
【发布时间】:2018-11-19 14:03:37
【问题描述】:

我正在用 React 编写 Conway 的生命游戏版本。组件的状态包含grid,描述了当前哪些单元格处于活动状态。在每个游戏循环中,都会计算新的grid,并在下一次迭代中更新状态。

我突然想到,由于setState是异步的,当用setInterval重复调用iterate函数时,我不能保证每次iterate运行时都使用当前版本的grid

是否有替代在 React 中使用 setInterval 的替代方法来避免 setState 异步导致的任何潜在问题?

以下是描述游戏循环的相关函数:

  go = () => {
    const { tickInterval } = this.state;
    this.timerId = setInterval(this.iterate, 570 - tickInterval);
    this.setState({
      running: true,
    });
  };

  iterate = () => {
    const { grid, gridSize, ticks } = this.state;
    const nextGrid = getNextIteration(grid, gridSize);
    this.setState({
      grid: nextGrid,
      ticks: ticks + 1,
    });
  };

【问题讨论】:

  • setState 可以采用callback function,该callback function 在新状态完全传播之后执行
  • this.timerId 来自 setInterval,我可以通过调用 clearInterval 轻松停止循环。使用回调,我猜回调函数将使用setTimeout?停止由回调函数组成的循环的方法是什么?

标签: javascript reactjs


【解决方案1】:

如果需要根据当前状态设置状态,直接依赖this.state是错误的,因为它可能会异步更新。您需要做的是将function 传递给setState 而不是对象:

this.setState((state, props) => ({
  // updated state
}));

在你的情况下,它会是这样的:

iterate = () => {

  this.setState(state => {
    const { grid, gridSize, ticks } = state;
    const nextGrid = getNextIteration(grid, gridSize);
    return {
      grid: nextGrid,
      ticks: ticks + 1
    }
  });

};

【讨论】:

    【解决方案2】:

    SetState 是异步的

    this.setState({
        running: true,
    });
    

    让它同步执行一个方法:

    this.setState({
         value: true
    }, function() {
        this.functionCall() 
    })
    

    【讨论】:

      【解决方案3】:

      如果您查看 react 官方文档,setState api 确实采用以下格式的回调:

      setState(updater[, callback])
      

      这里第一个参数将是您修改后的state 对象,第二个参数将是当setState 完成执行时要执行的回调函数。

      根据官方文档:

      setState() 并不总是立即更新组件。它可能 批处理或推迟更新。这使得阅读 this.state 就在调用 setState() 之后,这是一个潜在的陷阱。相反,使用 componentDidUpdate 或 setState 回调(setState(updater, 回调)),其中任何一个都保证在更新后触发 已应用。如果需要根据前面的设置状态 状态,请阅读下面的更新程序参数。

      您可以查看官方docs以获取更多信息。

      【讨论】:

      • 如果我正确理解了文档,我实际上不需要使用回调,提供给updater 函数的第一个参数将使用最新版本的state ,所以我认为来自 strletss 的答案更容易实现。