EffectScope 是 Vue 3.2+ 的副作用容器,用于统一管理 watch、computed 等响应式操作的生命周期,避免手动清理导致的内存泄漏;它通过 scope.run() 自动捕获副作用,调用 scope.stop() 一键清理,并支持嵌套与独立模式,可脱离组件在任意 JS 环境中复用。

EffectScope 是 Vue 3.2+ 引入的副作用容器,核心作用是把 watch、computed、watchEffect、effect 等响应式操作“打包”进一个可统一控制的生命周期单元里,避免手动逐个清理导致的内存泄漏和逻辑混乱。
它解决什么实际问题
在没有 EffectScope 时,开发者常这样管理副作用:
- 用
watch监听数据,再在onUnmounted里调用返回的 stop 函数 - 用
setTimeout/setInterval,自己存 ID 并手动清除 - 用
addEventListener,再配套removeEventListener
这些方式分散、易遗漏,尤其在组合式函数(如 useMouse、useApi)中,调用方根本不知道内部创建了哪些资源,更无法安全清理。
它是怎么工作的
EffectScope 本质是一个“注册表”,运行时通过 scope.run(() => { ... }) 激活作用域,并将其中创建的所有响应式副作用自动归属进来:
基于三引擎设计,从微信文章、新闻和博客网页提取干净内容,支持标题作者日期元数据,多格式和批量处理。
立即学习“前端免费学习笔记(深入)”;
- 所有
computed、watch、watchEffect、effect都会被自动捕获 - 甚至普通定时器、事件监听器,只要写在
run回调里,也能被scope.stop()一并处理(需配合手动清理逻辑封装) - 调用
scope.stop()后,内部所有响应式依赖被断开,计算属性停止更新,监听器失效,相关引用可被垃圾回收
常见使用模式
基础用法:显式创建并控制
- 创建作用域:
const scope = effectScope() - 注册副作用:
scope.run(() => { const count = ref(0); watch(count, ...) }) - 批量清理:
scope.stop()—— 一行代替多个 stop/clear/remove
嵌套与独立场景:
- 默认嵌套:子作用域随父作用域
stop()自动停止 - 独立作用域:
effectScope(true)创建 detached 实例,不受外部作用域影响,适合全局状态或插件级管理
和组件生命周期的关系
Vue 组件的 setup() 本身就在一个默认作用域中运行,组件卸载时自动 stop()。EffectScope 的价值在于把它“显式化”和“可复用”:
- 可在任意 JS 模块、工具函数、插件中创建,不依赖组件实例
- 可跨组件边界使用,比如在 Pinia store 或全局 API 封装中统一管理响应式逻辑
- 让组合式函数真正“自包含”——创建即注册,销毁即清理,调用方无需关心内部细节

















