effectscope 用于批量停止响应式监听,核心三步:创建作用域→scope.run 内注册副作用→调用 stop() 一键关停;适用于多清理逻辑、自定义 hook、动态启停监控及跨组件状态隔离等场景。

用 effectScope 批量停止响应式监听,核心就三步:创建作用域 → 在作用域内注册副作用 → 调用 stop() 一键关停。它不是锦上添花,而是解决手动清理遗漏、内存泄漏和组合式函数失控的刚需方案。
什么时候必须用 effectScope?
遇到以下情况,就该立刻引入:
- 组件里写了多个
onUnmounted清理逻辑(比如clearInterval+watch().stop()+removeEventListener) - 写自定义 Hook(如
useWebSocket、usePolling)时,内部创建了定时器或监听器,但调用方无法控制其生命周期 - 需要根据用户操作动态开启/关闭一整套监控逻辑(例如点击“开始追踪”后启动 watch + computed + 定时上报)
- 跨组件共享状态时,希望某组副作用只在当前业务流程中生效,退出即彻底销毁
基础用法:三步闭环
所有副作用必须在 scope.run(() => {}) 内定义,否则不会被收集:
-
创建作用域:
const scope = effectScope() -
运行副作用:
scope.run(() => { watch(...); computed(...); setInterval(...); }) -
批量关停:
scope.stop()—— 此刻所有内部watch失效、computed不再更新、定时器清除、onScopeDispose回调依次执行
进阶控制:嵌套、脱离与自定义清理
真实项目中常需更精细的管理能力:
-
嵌套作用域:子作用域自动跟随父作用域销毁。适合模块化封装,比如一个数据看板组件分“加载逻辑”“图表动画”“交互反馈”三块,各自用独立
effectScope(),顶层统一stop() -
独立作用域(detached):
effectScope({ detached: true })创建后不绑定当前活跃作用域,可用于插件级全局状态管理,避免被父组件卸载意外中断 -
注册自定义清理:在
scope.run内调用onScopeDispose(() => { /* 关闭 WebSocket、销毁第三方实例、移除原生事件监听 */ }),补全 Vue 原生 API 未覆盖的清理场景
高频避坑要点
这些细节不注意,effectScope 就等于没用:
- 副作用写在
scope.run外面 → 不会被收集,stop()对它完全无效 - 在 setup 外(比如普通工具函数、事件回调)调用
scope.run→ 可能因作用域上下文丢失导致绑定失败 - 误以为
scope.stop()会销毁ref或reactive数据 → 实际只停副作用,数据仍可读写,只是不再触发依赖更新 - 组件卸载时忘记调用
scope.stop()→ 即使用了 effectScope,不主动停等于白用










