使用React useEffect清理函数解决未挂载组件状态更新报错
React 「无法对已卸载组件执行状态更新」报错适配方案
核心原因
该报错本质是你调用的fetchShippingCountries、fetchSubdivisions、fetchShippingOptions都是异步请求,若组件在请求返回结果前就被卸载,请求回调里的状态更新操作依然会执行,就会触发内存泄漏提示。
适配后可用代码
你需要给每个useEffect都加上挂载状态标记、给异步回调加判断、补充清理逻辑,修改后的代码如下:
// 第一个useEffect:获取邮寄国家 useEffect(() => { let isMounted = true; fetchShippingCountries(checkoutToken.id) .then(res => { // 仅组件仍挂载时才执行状态更新 if (isMounted) { // 此处替换为你原来的回调逻辑,比如setShippingCountries(res) } }) .catch(err => { if (isMounted) { // 错误处理的状态更新也需加判断 } }); // 组件卸载时修改标记,阻止后续状态更新执行 return () => { isMounted = false; }; }, [checkoutToken.id]); // 第二个useEffect:获取地区/省份 useEffect(() => { if (!shippingCountry) return; let isMounted = true; fetchSubdivisions(shippingCountry) .then(res => { if (isMounted) { // 此处替换为你原来的状态更新逻辑,比如setSubdivisions(res) } }); return () => { isMounted = false; }; }, [shippingCountry]); // 第三个useEffect:获取邮寄选项 useEffect(() => { if (!shippingSubdivision) return; let isMounted = true; fetchShippingOptions(checkoutToken.id, shippingCountry, shippingSubdivision) .then(res => { if (isMounted) { // 此处替换为你原来的状态更新逻辑,比如setShippingOptions(res) } }); return () => { isMounted = false; }; }, [shippingSubdivision, checkoutToken.id, shippingCountry]);
之前套用失效的常见原因
- 只加了挂载变量声明和清理函数,没给异步请求的
then/catch回调里加isMounted判断 - useEffect的依赖项没有补全,出现闭包陷阱拿到了旧的变量值
- 若你使用的请求方法支持中断,也可以用
AbortController直接中断请求,比挂载标记的方案更彻底,示例如下:
useEffect(() => { const controller = new AbortController(); fetchShippingCountries(checkoutToken.id, { signal: controller.signal }) .then(res => { // 请求中断后不会进入then回调,可直接写状态更新逻辑 }) .catch(err => { if (err.name !== 'AbortError') { // 仅非主动中断的错误需要处理 } }); return () => { controller.abort(); // 组件卸载时直接中断未完成的请求 }; }, [checkoutToken.id]);
内容的提问来源于stack exchange,提问作者zelda3469
相关产品推荐
相关产品推荐

