React更新状态时重复发起API且旧请求未终止导致页面卡顿如何解决
解决方案
核心思路是每次发起新的API请求前,终止上一次未完成的旧请求,可以借助浏览器原生的AbortController实现,同时修复代码里的异步 setState 取值问题,具体修改步骤如下:
步骤1:在组件内初始化AbortController实例
在构造函数中声明变量存储控制器实例,用于后续终止请求,同时组件卸载时主动终止未完成的请求,避免内存泄漏:
constructor(props) { super(props); this.state = { startDate: null, endDate: null }; // 存储请求控制器 this.requestController = null; } componentWillUnmount() { // 组件卸载时终止未完成的请求 if (this.requestController) { this.requestController.abort(); } }
步骤2:改写fetchData方法,绑定终止信号
调用接口时把AbortController生成的signal传入请求配置,每次发起新请求前先终止上一次的请求:
fetchData = async (start, end) => { // 先终止上一次未完成的请求 if (this.requestController) { this.requestController.abort(); } // 新建控制器用于本次请求 this.requestController = new AbortController(); const signal = this.requestController.signal; try { // 把signal传入fetch配置(如果用axios的话对应传入cancelToken逻辑类似) const res = await fetch(`你的接口地址?start=${start}&end=${end}`, { signal: signal // 其他请求配置保持不变 }); const data = await res.json(); // 原有处理返回数据的逻辑保持不变 } catch (err) { // 主动abort触发的异常不需要处理,避免页面报错 if (err.name !== 'AbortError') { console.error('请求出错:', err); } } }
步骤3:修复updateDate的异步取值问题
setState是异步执行的,连续调用setState后直接读取state可能拿到的是旧值,直接把传入的start、end参数传给fetchData即可,不需要从state取值:
updateDate = (start, end) => { this.setState({ startDate: start, endDate: end }, () => { // 写在setState的回调里可确保state更新后再请求,也可以直接用参数调用更简单 this.fetchData(start.startDate, end.endDate); }); }
修改完成后只有最新的请求会被处理,旧请求会被直接终止,不会占用带宽和渲染资源,卡顿问题即可解决。如果项目用的是axios而非原生fetch,用axios自带的CancelToken实现请求取消,逻辑和上述方案完全一致。
内容的提问来源于stack exchange,提问作者Shota Donguzashvili
相关产品推荐
相关产品推荐

