javascript - 如何在触发新更新时等待或取消 componentDidUpdate 中的数据更新?

标签 javascript reactjs

我的问题

我正在使用 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 秒后改变状态。

尝试以下行为

  1. 点击Fetch B(没有任何反应)
  2. 快速点击Fetch A(出现来自A的数据)
  3. 等等
  4. (出现来自 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);

说明问题的图表

我创建了一个图表来显示我怀疑正在发生的事情

enter image description here


最佳答案

您可以使用实例变量来保存请求 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/

相关文章:

javascript - FlowType 使用什么语言来定义接口(interface)?

javascript - 如何将二维码转换为img并将其保存到firebase存储

javascript - 如何让这段代码看起来更好

javascript - 使摘要详细信息元素自动折叠

javascript - 在 javascript 中创建的 HTML 表单不响应 .submit

javascript - 当链接已经有 anchor 滚动时滚动到另一个页面上的位置

javascript - 如何在 react 路由器中将子路由定义为 react 组件?

javascript - 使用 dc.js 的日期堆积面积图

javascript - 将 &lt;input oninput= ... 与文本框中的当前值一起使用

css - 将图像放置在 View 中