在 React JS 的 this.setState 的回调中使用 this.setState?

Posted

技术标签:

【中文标题】在 React JS 的 this.setState 的回调中使用 this.setState?【英文标题】:Using this.setState in the callback of this.setState in React JS? 【发布时间】:2017-05-23 12:18:39 【问题描述】:

是否可以在this.setState的回调中调用this.setState?

我正在制作一个 Roguelike Dungeon 并且有一个设置,在 this.setState 的回调中使用了一个辅助函数,它再次调用 this.setState。我的游戏此时卡住了。

所以我在 React 组件中有一个对象,它具有生成随机二维数组映射的方法:

this.Dungeon.Generate();

游戏开始时,我们在componentDidMount()中调用组件中的如下函数:

componentDidMount: function() 

    this.Dungeon.Generate();

    this.setState(
      board: this.Dungeon.map
    , function() 

      this.generateGamePlay();

    );

  ,

this.generateGamePlay() 看起来像这样,基本上随机生成并放置玩家、老板和物品在板上:

generateGamePlay: function() 

var board = this.state.board.slice();

var startPosition = this.randomPosition();

board[startPosition[0]][startPosition[1]] = this.state.player;

var bossPosition = this.randomPosition();

board[bossPosition[0]][bossPosition[1]] = this.state.boss[this.state.dungeonLevel];

this.generateWeapons(this.state.dungeonLevel,board);

this.generateFood(this.state.dungeonLevel, board);

this.generateEnemies(this.state.dungeonLevel, board);

this.setState(
  board: board
);

 ,

但是当玩家死亡时,我们再次调用上面的方法来重置游戏:

this.Dungeon.Generate();
        //generate a new dungeon map, available in this.Dungeon.map

        this.setState(
          board: this.Dungeon.map, currentMessage: "Game restarted", player: player, weapon: weapon, dungeonLevel: 0
          , function()

                this.generateGamePlay();

          )

然后是我的游戏冻结的时候。所以我第一次调用this.generateGamePlay()(调用this.setState)时它可以工作,但第二次它冻结了。谁能帮帮我?

【问题讨论】:

是的,您可以在另一个setState() 的回调中调用setState()。冻结很可能与回调本身无关。 【参考方案1】:

我会看看你在状态中设置 this.Dungeon.map 的部分。

this.setState(
          board: this.Dungeon.map, currentMessage: "Game restarted", player: player, weapon: weapon, dungeonLevel: 0
          , function()

                this.generateGamePlay();

          )

我的猜测是其他东西可能正在更改地图对象而不使用 setstate,因为它是 Dungeon 的属性。

来自react docs

永远不要直接改变 this.state,因为之后调用 setState() 可能 替换您所做的突变。把 this.state 当作是 不可变。

当您将 map 属性传递给 setstate 时,它​​将保留对 this.Dungeon.map 的引用,如果您随后对其进行修改将导致问题。您应该复制 .map 的内容并将其传递给 state。

您还应该让一个组件负责状态,而不是在不同的函数中多次调用它。来自react docs

setState() 不会立即改变 this.state 而是创建一个 等待状态转换。调用 this 后访问 this.state 方法可能会返回现有值。

不保证 setState 调用的同步操作 并且调用可能会被批处理以提高性能。

由于所有多个 setstate 调用,您的冻结可能来自渲染方法中的竞争条件。

【讨论】:

【参考方案2】:

就像弗兰克的代码一样,我有这个:

this.setState( state => 
  state.board = this.Dungeon.map
  return state
)

我希望它对你有用,或者我做错了,或者误解了你的问题

【讨论】:

这会改变旧状态,它是 React 中未定义的行为(反模式,不鼓励)。

以上是关于在 React JS 的 this.setState 的回调中使用 this.setState?的主要内容,如果未能解决你的问题,请参考以下文章

React 如何更新另一个组件的状态?

如何重新渲染平面列表?

在render()中更新状态时,防止无限循环

React 、React.js、React Native三者关系

在Node.js上搭建React.js开发环境

React.js Chrome 扩展 - 如何将 Background.js 中的数据存储在 React 内部的变量中?