React切换组件时出现Can't perform state update内存泄漏报错如何解决
问题根因
你当前使用的AbortController完全没有生效,核心有两点错误:
- 你只是创建了AbortController实例,没有将它的
signal参数传递给getDecodedMedia内部的异步请求,请求和取消信号没有任何关联,即使调用abort方法,请求还是会正常执行完毕 - 你写的
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
相关产品推荐
相关产品推荐

