我有一个不支持generators
和async await
语法的项目。
我使用async await
构建了以下代码,因为我没有看到任何其他方法来执行此操作:
this.setState(async lastState => {
const newImagesAmount = lastState.images.length + 20;
const newImages = await this.getImages(this.props.tag, newImagesAmount);
return {
images: newImages
};
});
为什么?在这种特殊情况下,新状态由旧状态和promise
的结果构建。
如何将其转换为非async await
语法?
由于当前答案都包含相同的错误,please read @dhilt answer + responses首先解释了什么是错误。
首先,在await
中使用setState()
是不可能的。不是因为你的项目的限制,而是因为内部有await
的每个函数都应该事先声明为async
。它应该用await
表示法或用.then()
链接来调用。因此传递到.setState
的回调应该是async
并且用await
调用,但我们知道React不会这样工作。 React期望普通函数并在没有await
或.then()
的情况下调用它。它看起来像func.apply(context, funcArgs)
模块中的react-dom
。也没有检查它是否返回Promise。
那么让我们回到你的最终目标。据我所知,它是关于在加载延迟数据后确保状态仍然一致。这是另一个限制。除了同步XHR(这是非常糟糕的做法)之外,在数据到来之前无法暂停所有执行。那就是:无论你做什么,你都不能100%确定state
在“请求已发送”和“数据已收到”步骤之间没有变异。 await
和功能性setState
都不允许冻结执行。是的,您的代码仍然引用“prevState”变量,但它可能不再是实际组件的状态!
那你可以做什么:
附:因此,从setState
函数内部发出请求会导致混淆,并且不会增加任何额外的灵活性。
如果问题中的代码是正确的,并且您只想清除async / await以支持传统的return promise.then(...)
语法,那么请执行以下操作:
this.setState(lastState => {
const newImagesAmount = lastState.images.length + 20;
return this.getImages(this.props.tag, newImagesAmount)
.then(newImages => ({ 'images': newImages });
});
以下简化也可能有效:
this.setState(lastState => {
return this.getImages(this.props.tag, lastState.images.length + 20)
.then(images => ({ images });
});
我假设这里的lastState实际上只是你更新它之前的当前状态。尝试这样的事情:
const imageLength = this.state.images.length + 20
this.getImages(this.props.tag, imageLength)
.then(newImages => {
this.setState({images: newImages})
}
我想你可能想要这样的东西
const newImagesAmount = this.state.images.length + 20;
this.getImages(this.props.tag, newImagesAmount).then(newImages =>
this.setState(prevState => ({
..prevState,
images: newImages
})
);
首先,您请求新图像,此请求基于当前状态。然后(当结果到达时),您更新状态。
更新版本,允许在请求完成之前保护异步逻辑免于多次执行
if (!this.state.pending) {
this.setState(lastState => {
const newImagesAmount = lastState.images.length + 20;
this.getImages(this.props.tag, newImagesAmount).then(newImages =>
this.setState(prevState => ({
...prevState,
pending: false,
images: newImages
})
).catch(() =>
this.setState(prevState => ({
...prevState,
pending: false
})
);
return {
...lastState,
pending: true
}
});
}