我正在基于间隔创建游戏。父组件创建一个间隔,并让其子组件注册每个间隔触发的回调。
我的设置看起来像
<ParentComponent>
<Child1 />
<Child2 />
...
</ParentComponent>
父母使用React.cloneElement
并为每个孩子提供一种方法
registerCallback( callback, id ) {
const { callbacks } = this.state;
this.setState({
callbacks: callbacks.concat({
callback,
id
})
})
}
这种方法效果很好。但是现在我有两个孩子从registerCallback()
内部调用componentDidMount()
方法。
现在只有<Child2 />
将其回调存储在父状态中。
当我像这样延迟registerCallback()
方法的调用
setTimeout(() => {
registerCallback(callbackFunction, id)
}, 50 )
工作正常。但这感觉是一个非常错误的破解,尤其是因为我需要“猜测”状态需要更新多长时间。
所以我的结论是状态更新太慢了,而是在组件外部定义了一个数组,然后更新了它。奇怪的是,如果我对该数组进行了变异,它就可以正常工作。
所以如果我用
array.push({callback, id})
我的数组看起来像[callback1, callback2]
但是由于我不想改变数组,所以我尝试了
array.concat({callback, id})
这给我留下了[]
我的状态看起来像[array2]
我该如何改善在父级中的方法,使子级可以随时随地调用registerCallback()
。
答案 0 :(得分:2)
您已经正确推断出问题是setState是异步的,因此到第二个子对象调用registerCallback时,第一个子对象的状态更改尚未传播到this.state。试试:
registerCallback( callback, id ) {
this.setState(({ callbacks }) => ({
callbacks: callbacks.concat({
callback,
id
})
})
}
您将一个函数作为第一个参数传递给setState。此函数接收当前状态(以上为{ callbacks }
的结构),并应返回新状态。该函数将立即或在先前的状态更改传播后被调用,因此可以确保其状态是最新的。因此,避免使用可能过时的this.state
。
这是一篇有关它的文章:
https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3