You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React重新请求数据时页面卡顿冻结是什么原因?

问题根因
  • 死循环触发无限渲染:componentDidUpdate 生命周期中,判断 startDate 变更后,又调用 updateStartDate、updateEndDate 重复设置相同的 state,会再次触发 componentDidUpdate,形成无限递归循环,CPU和内存占用持续升高,多次触发后就会导致页面冻结。你添加的 shouldComponentUpdate 刚好拦截了部分无效更新,所以问题有轻微缓解。
  • 未处理请求竞态与内存泄漏:多次发起的请求没有取消机制,旧请求返回后依然会执行 setState 触发不必要的渲染,短时间内大量请求叠加会占用过多浏览器资源。同时 componentDidMount 中的 setTimeout 没有清理逻辑,组件卸载后仍可能执行,也会引发内存泄漏。
  • 状态更新逻辑冗余:日期变更的状态更新应该由日期选择组件的回调触发,不需要在 componentDidUpdate 中重复设置已经变更完成的状态。
解决方案

1. 修复componentDidUpdate死循环

直接移除componentDidUpdate中冗余的状态更新调用,修改后代码如下:

componentDidUpdate(prevProps, prevState){
  if(this.state.startDate !== prevState.startDate || this.state.endDate !== prevState.endDate){
    // 只需要重新发起请求,不要重复设置已经更新的startDate/endDate
    this.fetchData(this.state.startDate, this.state.endDate);
    this.fetchUniqueData(this.state.startDate, this.state.endDate)
  }
}

// 这两个函数保留,给日期选择器的onChange事件调用即可
updateStartDate = (start) => {
  this.setState({startDate: start})        
}
updateEndDate = (end) => {
  this.setState({endDate: end})
}

2. 添加请求取消机制

使用AbortController在发起新请求前取消上一次未完成的请求,避免无效更新:

class YourComponent extends React.Component {
  // 声明abort控制器和定时器id
  fetchAbortController = null;
  timerId = null;

  async fetchData(start, end) {
    try {
      // 取消上一次未完成的请求
      if(this.fetchAbortController) this.fetchAbortController.abort();
      this.fetchAbortController = new AbortController();

      const URL = "exampleUrl";
      var myHeaders = new Headers();
      myHeaders.append("Authorization", "exampleToken");

      let formdata = new FormData();
      formdata.append("act", "report1");
      formdata.append("data", `{"start_date": "${start}", "end_date": "${end}"}`);

      var requestOptions = {
        method: "POST",
        headers: myHeaders,
        body: formdata,
        redirect: "follow",
        // 关联abort信号
        signal: this.fetchAbortController.signal
      };
      const response = await fetch(URL, requestOptions)
      const json = await response.json()
      this.setState({data: json.data})
    } catch (err) {
      // 忽略abort产生的错误
      if(err.name !== 'AbortError') console.log(err);
    }
  }

  componentDidMount() {    
    this.currentDate();
    this.addRow()
    this.fetchData(this.state.startDate, this.state.endDate);
    this.fetchUniqueData(this.state.startDate, this.state.endDate);
    this.handleRow();
    // 保存定时器id
    this.timerId = setTimeout(() => {
      for (let i = 0; i < 11; i++) {
          this.fillCheckboxes(i);
      }
    }, 500);
  }

  componentWillUnmount() {
    // 组件卸载时取消请求和清除定时器
    if(this.fetchAbortController) this.fetchAbortController.abort();
    if(this.timerId) clearTimeout(this.timerId);
  }

  // 其他代码...
}

3. 优化渲染判断逻辑

完善shouldComponentUpdate的判断条件,覆盖所有需要触发渲染的状态字段:

shouldComponentUpdate(nextProps, nextState) {
  return this.state.startDate !== nextState.startDate 
    || this.state.endDate !== nextState.endDate
    || this.state.data !== nextState.data;
}

如果组件的状态都是基础类型或浅比较可区分的引用类型,也可以直接继承React.PureComponent,自动实现浅比较的shouldComponentUpdate。

4. 可选优化:添加请求防抖

如果日期选择器支持连续调整(比如日期滚轮),可以给请求添加300ms左右的防抖,避免短时间内发起大量无效请求。

内容的提问来源于stack exchange,提问作者Shota Donguzashvili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 01:24:05