我的问题
我正在使用 componentDidUpdate
如果 props 已更改,则获取数据并更新组件状态。这是 React 文档的建议:
This is also a good place to do network requests as long as you compare the current props to previous props
但是,如果我触发一个更新的网络请求恰好比前一个更新触发的响应更快,状态将用新请求更新,然后用旧请求覆盖。这不是我想要的:我希望使用最新更新触发的请求中的数据更新状态。
如何在触发新更新时等待或取消 componentDidUpdate 中的数据更新?
重现问题
为了说得更清楚,我写了一个小例子来模拟这种情况,你可以try it out on code sandbox .有两个按钮,一个立即改变状态,另一个在 2 秒后改变状态。
尝试以下行为
- 点击
Fetch B
(没有任何反应) - 快速点击
Fetch A
(出现来自A的数据) - 等等
- (出现来自 B 的数据)
然而,用户会希望 Data from A
保留下来,因为它是最后一个被点击的按钮。
上传到 CodeSandbox 的示例代码,以防链接断开
import React, { Component } from "react";
import ReactDOM from "react-dom";
class Display extends Component {
constructor(props) {
super(props);
this.state = {
show: ""
};
}
componentDidUpdate(prevProps) {
if (this.props.show !== prevProps.show) {
const timeout = this.props.show === "A" ? 0 : 2000;
const show = this.props.show === "A" ? "Data from A" : "Data from B";
setTimeout(() => {
this.setState({ show });
}, timeout);
}
}
render() {
return <div>{this.state.show}</div>;
}
}
class ChangeInput extends Component {
constructor(props) {
super(props);
this.state = {
selected: ""
};
}
handleEventA = () => {
this.setState({ selected: "A" });
};
handleEventB = () => {
this.setState({ selected: "B" });
};
render() {
return (
<div>
<button type="button" onClick={this.handleEventA}>
Fetch A (fast)
</button>
<button type="button" onClick={this.handleEventB}>
Fetch B (slow)
</button>
<Display show={this.state.selected} />
</div>
);
}
}
export default ChangeInput;
const rootElement = document.getElementById("root");
ReactDOM.render(<ChangeInput />, rootElement);
说明问题的图表
我创建了一个图表来显示我怀疑正在发生的事情
最佳答案
您可以使用实例变量来保存请求 ID,并在更新状态之前检查请求 ID 是否为最后一个。用代码更清楚:
constructor(props) {
super(props);
this.state = {
show: ""
};
this.lastRequestId = null;
}
componentDidUpdate(prevProps) {
if (this.props.show !== prevProps.show) {
const timeout = this.props.show === "A" ? 0 : 2000;
const show = this.props.show === "A" ? "Data from A" : "Data from B";
const requestId = `REQUEST-${Date.now()}`;
this.lastRequestId = requestId;
setTimeout(() => {
if (this.lastRequestId !== requestId) {
console.log('Request canceled ...');
return;
}
this.setState({ show });
}, timeout);
}
}
完整代码:https://codesandbox.io/s/componentdidupdate-conflict-t4rfj
关于javascript - 如何在触发新更新时等待或取消 componentDidUpdate 中的数据更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57995039/