如何解决React报错:无法在已卸载组件上执行状态更新
解决React组件卸载后异步请求更新状态的警告问题
当组件发起异步请求后,在请求完成前切换页面导致组件卸载,此时请求响应回来后调用setState就会触发Warning: Can't perform a React state update on an unmounted component警告——因为组件实例已经不存在了。AbortController完全适用于这个场景,你之前没成功应该是用法不对,下面是具体的解决步骤:
1. 修改Axios工具函数,支持传入终止信号
首先需要让你的apiGetCall函数接受AbortController的signal参数,这样才能在组件卸载时取消请求:
// axios utils export const apiGetCall = (url, signal) => axiosInstance.get(url, { signal });
2. 在组件的useEffect中使用AbortController并添加挂载状态检查
在发起请求的useEffect里,创建AbortController实例,把signal传给请求,同时设置一个isMounted标志位作为双重保险,组件卸载时更新这个标志并终止请求:
useEffect(() => { const abortController = new AbortController(); let isMounted = true; // 标记组件是否仍挂载 const fetchData = async () => { try { // 将signal传入请求 const response = await apiGetCall("/departments", abortController.signal); const departmentsData = response.data.departments; // 只有组件仍挂载时才更新状态 if (isMounted) { setDepartmentData(departmentsData); setPieChartOptions({ // 部门数据配置 }); } } catch (err) { // 忽略请求被主动取消的错误,只处理其他异常 if (!axios.isCancel(err)) { console.log(err); } } }; fetchData(); // 组件卸载时执行清理:更新挂载状态+终止请求 return () => { isMounted = false; abortController.abort(); }; }, []);
3. 对三个请求逐一处理
你的组件有三个独立请求,需要给每个请求都应用上述逻辑(可以复用同一个AbortController来终止所有请求,也可以每个请求单独创建,效果一致)。比如用同一个控制器并行处理三个请求:
useEffect(() => { const abortController = new AbortController(); let isMounted = true; const fetchDepartments = async () => { try { const response = await apiGetCall("/departments", abortController.signal); if (isMounted) { // 更新部门相关状态 } } catch (err) { if (!axios.isCancel(err)) console.log(err); } }; const fetchChart2Data = async () => { try { const response = await apiGetCall("/chart2-data", abortController.signal); if (isMounted) { // 更新图表2相关状态 } } catch (err) { if (!axios.isCancel(err)) console.log(err); } }; const fetchChart3Data = async () => { try { const response = await apiGetCall("/chart3-data", abortController.signal); if (isMounted) { // 更新图表3相关状态 } } catch (err) { if (!axios.isCancel(err)) console.log(err); } }; // 并行发起三个请求 Promise.all([fetchDepartments(), fetchChart2Data(), fetchChart3Data()]); return () => { isMounted = false; abortController.abort(); }; }, []);
这样修改后,当你切换页面卸载组件时,会立即终止所有未完成的请求,同时即使请求已经进入响应阶段,也会通过isMounted标志跳过状态更新,彻底解决这个警告问题。
内容的提问来源于stack exchange,提问作者raio
相关产品推荐
相关产品推荐

