React触发Can't perform a React state update on an unmounted警告如何解决
问题根因
你当前编写的isMounted判断逻辑存在位置错误,是触发警告的直接原因:
- 你只在异步函数开头判断了
isMounted状态,发起getCurrencies请求前组件处于挂载状态,就会执行setIsLoading(true)并发起异步请求 - 若请求等待过程中组件被卸载,useEffect清理函数会将
isMounted置为false,但已经发起的异步请求不会中断 - 请求返回后,代码会直接执行await之后的
setCurrenciesOptions、setIsLoading(false)逻辑,这两个状态更新没有做挂载状态判断,就会触发「卸载组件不能更新状态」的警告
修复方案
有两种可选修复方式,按需选择即可:
方式1:仅补充挂载状态判断(最简单)
调整异步逻辑的判断位置,每次异步操作返回后先校验组件是否还挂载,未挂载直接终止后续逻辑:
useEffect(() => { let isMounted = true; const prepareCurrenciesOptions = async () => { try { setIsLoading(true); const currencies = await (await getCurrencies()).json(); // 异步返回后先判断挂载状态 if (!isMounted) return; const preparedData = getCurrenciesOptionsData(currencies); setCurrenciesOptions(preparedData); setIsLoading(false); } catch (err) { console.error(err); } }; prepareCurrenciesOptions(); return () => { isMounted = false; }; }, []);
方式2:补充请求取消逻辑(更彻底)
使用AbortController在组件卸载时直接取消未完成的请求,同时避免无效的后续逻辑执行,还能节省无效请求流量:
useEffect(() => { let isMounted = true; const abortController = new AbortController(); const prepareCurrenciesOptions = async () => { try { setIsLoading(true); // 将取消信号传入getCurrencies方法,需要你的getCurrencies支持接收signal参数 const currenciesRes = await getCurrencies(abortController.signal); const currencies = await currenciesRes.json(); if (!isMounted) return; const preparedData = getCurrenciesOptionsData(currencies); setCurrenciesOptions(preparedData); setIsLoading(false); } catch (err) { // 忽略请求主动取消的报错 if (err.name !== 'AbortError') { console.error(err); } } }; prepareCurrenciesOptions(); return () => { isMounted = false; abortController.abort(); }; }, []);
通用排查方法
如果后续遇到同类问题,可以按以下步骤快速定位:
- 优先看报错栈里标记的组件名,你本次的报错已经明确指向
CurrencySelect组件,直接检查该组件内的异步逻辑即可 - 遍历组件内所有useEffect,检查异步任务、定时器、事件订阅等逻辑有没有对应的清理逻辑
- 可以在状态更新逻辑前打印挂载状态标记,确认是否是组件卸载后触发的更新
内容的提问来源于stack exchange,提问作者maaajo
相关产品推荐
相关产品推荐

