不同的 Child 组件通过同时调用 setState 弄乱了 parent 的状态

Different Child Components mess up State of parent by calling setState at the same time

我正在创建一个基于间隔的游戏。 parent 组件创建一个时间间隔并让其 children 注册每个时间间隔触发的回调。

我的设置看起来像

<ParentComponent>
  <Child1 />
  <Child2 />
  ...
</ParentComponent>

parent 使用 React.cloneElement 并为每个 child

提供一个方法
registerCallback( callback, id ) {
  const { callbacks } = this.state;
    this.setState({
      callbacks: callbacks.concat({
        callback,
        id
      })
    })
  }

这种方法效果很好。但是现在我有两个 children 从 componentDidMount().

中调用 registerCallback() 方法

现在只有 <Child2 /> 将其回调存储在 parents 状态。

当我延迟 registerCallback() 方法的调用时

setTimeout(() => {
  registerCallback(callbackFunction, id)
}, 50 )

它运行良好。但这感觉像是一个非常错误的 hack,特别是因为我需要 "guess" 状态需要更新多长时间。

所以我的结论是状态更新太慢了,而是在我的组件之外定义了一个数组并更新了它。奇怪的是,如果我改变这个数组,它就可以正常工作。

所以如果我使用 array.push({callback, id}) 我的数组看起来像 [callback1, callback2]

但是因为我不想改变我的数组我试过了 array.concat({callback, id}) 这给我留下了 []

虽然我的状态看起来像 [array2]

我怎样才能在 parent 中改进我的方法,让 children 可以随时随地毫无问题地调用 registerCallback()

正如您正确推断的那样,问题是 setState 是异步的,因此到第二个 child 调用 registerCallback 时,第一个 child 的状态更改尚未传播到 this.state.尝试:

registerCallback( callback, id ) { this.setState(({ callbacks }) => ({ callbacks: callbacks.concat({ callback, id }) }) }

您将函数作为第一个参数传递给 setState。此函数接收当前状态(上面解构为 { callbacks })并且应该 return 新状态。该函数将立即被调用,或者在先前的状态更改传播时被调用,因此它的状态保证是新鲜的。因此,您避免使用可能过时的 this.state.

这是一篇关于它的文章:

https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3