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

React内存泄漏问题求助:useEffect清理及isMounted用法验证

修复React组件卸载后状态更新的内存泄漏问题

你遇到的这个错误是因为组件已经卸载,但异步请求完成后仍尝试更新状态,导致内存泄漏。你的isMounted思路方向是对的,但代码里有两个关键问题需要修正,同时还有更规范的解决方案:

问题分析

  1. 无限循环隐患:你的useEffect依赖了initialState,每次调用setInitialState都会触发useEffect重新执行,进而再次调用setInitialState,形成无限循环,会加剧内存泄漏问题。
  2. isMounted判断时机错误:你把isMounted判断放在了async函数外面,组件在await Api.controllerList()期间卸载的话,异步操作完成后仍然会执行setInitialState,没起到拦截作用。

方案一:修正isMounted的使用方式

export default function Controllers() {
    const [initialState, setInitialState] = useState<PageState>({ controllers: [] });
    const [showModal, setShowModal] = useState<Boolean>(false);
    const [existing, setExisting] = useState<IController>();

    useEffect(() => {
        let isMounted = true;

        const fetchControllers = async () => {
            const controllers = await Api.controllerList();
            // 仅在组件挂载时更新状态
            if (isMounted) {
                setInitialState({ controllers });
            }
        };  

        fetchControllers();  

        // 组件卸载时标记为未挂载
        return () => { 
            isMounted = false; 
        };
    }, []); // 依赖改为空数组,仅在组件挂载时执行一次
}

关键修正点:

  • 把useEffect的依赖改为空数组[],确保只在组件挂载时执行一次数据请求,避免无限循环。
  • 将isMounted的判断移到await之后,确保异步请求完成后先检查组件是否还挂载,再执行状态更新。

方案二:使用AbortController取消异步请求(更规范)

手动标记isMounted只是拦截状态更新,但网络请求本身已经发出去了。用AbortController可以直接取消未完成的请求,更高效也更符合React最佳实践:

export default function Controllers() {
    const [initialState, setInitialState] = useState<PageState>({ controllers: [] });
    const [showModal, setShowModal] = useState<Boolean>(false);
    const [existing, setExisting] = useState<IController>();

    useEffect(() => {
        const abortController = new AbortController();
        const signal = abortController.signal;

        const fetchControllers = async () => {
            try {
                // 把signal传入请求,支持取消操作
                const controllers = await Api.controllerList({ signal });
                setInitialState({ controllers });
            } catch (error) {
                // 忽略取消请求导致的错误
                if (error.name !== 'AbortError') {
                    console.error('请求失败:', error);
                }
            }
        };  

        fetchControllers();  

        // 组件卸载时取消请求
        return () => { 
            abortController.abort(); 
        };
    }, []);
}

注意事项:

  • 需要确保你的Api.controllerList方法支持接收signal参数,并将其传递给底层的fetch或axios请求(比如axios的cancelToken或者fetch的signal)。
  • 取消请求会抛出AbortError,需要在catch块中过滤这个错误,避免不必要的报错信息。

内容的提问来源于stack exchange,提问作者Plamen Chichkov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:35:13