组件销毁时必须主动取消订阅、清除定时器、解绑事件监听器并中止异步请求,否则会导致内存泄漏或“在已卸载组件上执行状态更新”错误;react 用 useeffect 清理函数,vue 3 用 onbeforeunmount,核心是创建与清理严格配对。

在 JavaScript(尤其是 React、Vue 等框架)中,组件销毁时未清理订阅(如事件监听器、RxJS Observable、定时器、Promise 回调等),容易导致内存泄漏或“在已卸载组件上执行状态更新”这类错误。关键不是“删除引用”,而是主动取消订阅、移除监听、清除副作用。
React 中:useEffect 清理函数是标准做法
React 的 useEffect 允许返回一个清理函数,它会在组件卸载前或依赖项变化前自动执行:
- 对事件监听器:用
addEventListener添加,就在清理函数里用removeEventListener移除; - 对 RxJS 订阅:调用
subscription.unsubscribe(); - 对定时器:
clearTimeout或clearInterval; - 对 Promise 链(如 fetch):可用 AbortController 控制请求中止,避免 .then 中 setState。
示例(RxJS):
const subscription = useEffect(() => {const sub = dataStream$.subscribe(x => setState(x));
return () => sub.unsubscribe(); // ✅ 自动清理
}, []);
Vue 3 中:onBeforeUnmount 是推荐时机
在组合式 API 中,使用 onBeforeUnmount 钩子执行清理逻辑:
- 手动调用
unwatch停止响应式监听; - 调用
subscription.unsubscribe(); - 移除全局事件(
window.removeEventListener); - 清除
setTimeout/setInterval句柄。
示例(自定义事件监听):
const handler = () => console.log('resize');window.addEventListener('resize', handler);
onBeforeUnmount(() => {
window.removeEventListener('resize', handler); // ✅
});
通用原则:谁创建,谁负责清理
只要代码中显式建立了长期存活的引用关系,就要配对清理:
- 不要依赖垃圾回收自动解绑 —— 闭包、事件监听器、Observable 内部持有 this 引用,会阻止组件实例被回收;
-
避免在异步回调中直接操作组件状态 —— 可加标记位(如
isMounted = true/false)判断,但更推荐用清理机制直接中断; -
第三方库通常提供取消方法 —— 如
axios.CancelToken、AbortSignal、useSWR的mutate或配置revalidateOnMount: false等。
小技巧:封装可清理的订阅工具
可抽象一个带自动清理能力的 hook 或 composable,比如:
- React:
useSubscription封装 Observable 订阅 + 自动 unsubscribe; - Vue:
useEvent返回带stop方法的监听器; - 通用:
createDisposable返回{ value, dispose },统一管理生命周期。
这样能减少重复写清理逻辑,也降低遗漏风险。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











