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

React切换组件时出现Can't perform state update内存泄漏报错如何解决

问题根因

你当前使用的AbortController完全没有生效,核心有两点错误:

  1. 你只是创建了AbortController实例,没有将它的signal参数传递给getDecodedMedia内部的异步请求,请求和取消信号没有任何关联,即使调用abort方法,请求还是会正常执行完毕
  2. 你写的getURL(s3Key).then(() => abortController.abort())逻辑完全错误,相当于等异步请求执行完成后再主动取消请求,起不到任何提前终止的作用

请求执行完毕后调用setVideoLink更新状态时,组件已经卸载,就会抛出对应警告。

解决方案

方案1:绑定取消信号(推荐)

首先修改getDecodedMedia方法,支持接收AbortSignal参数,传入内部的请求实例中:

// 示例为fetch请求写法,axios等请求库同理,都支持传入signal参数
export const getDecodedMedia = async (key: string, signal?: AbortSignal) => {
  const response = await fetch(`你的S3签名请求地址/${key}`, { signal });
  return response.text();
};

再修改组件内的useEffect逻辑:

useEffect(() => {
  const abortController = new AbortController();
  const getURL = async (key: string) => {
    try {
      const link = await getDecodedMedia(key, abortController.signal);
      setVideoLink(link as string);
    } catch (err) {
      // 跳过请求被主动取消抛出的AbortError
      if ((err as Error).name !== 'AbortError') {
        console.error('获取视频地址失败', err);
      }
    }
  };
  getURL(s3Key);
  // 组件卸载时主动取消请求
  return () => abortController.abort();
}, [s3Key]);

方案2:挂载状态兜底(无需修改底层方法)

如果不方便改动getDecodedMedia的逻辑,可以用挂载状态标记作为兜底,只有组件还处于挂载状态时才更新state:

useEffect(() => {
  let isMounted = true;
  const getURL = async (key: string) => {
    const link = await getDecodedMedia(key);
    if (isMounted) {
      setVideoLink(link as string);
    }
  };
  getURL(s3Key);
  // 组件卸载时标记为未挂载
  return () => {
    isMounted = false;
  };
}, [s3Key]);
额外排查点

如果以上方案修改后仍然有警告,检查以下两点:

  • 确认getDecodedMedia内部没有其他未处理的异步回调逻辑
  • 你已经给ReactPlayer设置了stopOnUnmount={true},如果还有警告可以升级ReactPlayer到最新版本,排除组件内部的已知BUG

内容的提问来源于stack exchange,提问作者Ihtisam Arif

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:54:00