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

如何让已挂起组件卸载时执行useEffect的清理函数?

解决组件挂起后卸载时useEffect清理函数不执行的问题

当组件抛出Suspense异常进入挂起状态时,它还未完成commit阶段,useEffect的回调函数根本没有机会执行——而清理函数只有在effect被执行过的前提下,才会在组件卸载或依赖更新时运行,这就是导致内存泄漏的核心原因。

以下是几种可行的解决方案:

方案1:触发挂起前手动执行清理

通过useRef存储清理函数,在触发挂起的操作中先手动调用清理逻辑,再切换挂起状态:

function Foo() {
  const [isSuspended, setIsSuspended] = useState(false);
  const cleanupRef = useRef(null);

  useEffect(() => {
    const eventHandler = () => {
      // 你的事件处理逻辑
    };
    window.addEventListener('resize', eventHandler);

    // 将清理函数存入ref
    cleanupRef.current = () => {
      window.removeEventListener('resize', eventHandler);
    };

    return cleanupRef.current;
  }, []);

  const handleTriggerSuspend = () => {
    // 先手动执行清理
    if (cleanupRef.current) {
      cleanupRef.current();
      cleanupRef.current = null;
    }
    // 再触发挂起
    setIsSuspended(true);
  };

  if (isSuspended) {
    throw new Promise(resolve => setTimeout(resolve, 1500)); // 模拟Suspense异步操作
  }

  return <button onClick={handleTriggerSuspend}>触发挂起</button>;
}

方案2:用状态控制effect的激活状态

通过额外的状态变量控制effect是否执行,在触发挂起前先关闭effect,等待清理完成后再切换挂起状态:

function Foo() {
  const [isSuspended, setIsSuspended] = useState(false);
  const [isEffectEnabled, setIsEffectEnabled] = useState(true);

  useEffect(() => {
    if (!isEffectEnabled) return;

    const eventHandler = () => {
      // 你的事件处理逻辑
    };
    window.addEventListener('resize', eventHandler);

    return () => {
      window.removeEventListener('resize', eventHandler);
    };
  }, [isEffectEnabled]);

  const handleTriggerSuspend = () => {
    // 先禁用effect,触发清理
    setIsEffectEnabled(false);
    // 延迟触发挂起,确保清理逻辑执行完成
    setTimeout(() => setIsSuspended(true), 0);
  };

  if (isSuspended) {
    throw new Promise(resolve => setTimeout(resolve, 1500));
  }

  return <button onClick={handleTriggerSuspend}>触发挂起</button>;
}

方案3:重构为标准Suspense资源加载

如果挂起逻辑基于数据加载,建议将异步资源封装为React Suspense兼容的资源(比如自定义资源管理器),而非在组件内部直接抛出异常。这种模式下,组件只有在资源加载完成后才会渲染并执行effect;若组件在资源加载完成前卸载,由于effect从未执行过,也就不存在需要清理的资源,从根源避免泄漏问题。

内容的提问来源于stack exchange,提问作者Leo Jiang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:23:14