effectScope 可统一销毁多个 watch/watchEffect:在 scope.run() 内创建的响应式副作用自动归属该作用域,调用 scope.stop() 即全部关停;配合 onScopeDispose 可清理定时器等非响应式资源,并推荐在 onMounted 创建、onUnmounted 停止以对齐组件生命周期。

在 effectScope 中统一销毁多个 watch 和 watchEffect,核心是把它们“放进同一个容器”,再用一次 scope.stop() 全部关停——不需要逐个调用各自的 stop 函数。
所有 watch/watchEffect 自动归属作用域
只要在 scope.run(() => { ... }) 内创建,Vue 就会自动将这些响应式副作用注册到该作用域下:
-
watch()、watchEffect()、computed()都会被自动收纳 - 即使嵌套调用(比如在
watch回调里又新建一个watchEffect),只要还在run的同步执行上下文中,就属于当前 scope - 作用域外创建的监听器不受影响,不会被误停
一键 stop 就够了,无需手动保存每个 stop 函数
传统方式要分别存 const stop1 = watch(...)、const stop2 = watchEffect(...),再一一调用;而用 effectScope 后,这个过程完全自动化:
-
scope.stop()会遍历内部所有已注册的 watcher 和 effect,依次触发它们的清理逻辑 -
watch停止依赖追踪,不再响应变化 -
watchEffect彻底静默,不重新执行,也不再收集依赖 - 已停止的作用域不可恢复,再次
run不生效,需新建 scope
配合 onScopeDispose 处理非响应式资源
如果监听器内部启动了定时器、事件监听或请求,仅靠 scope.stop() 还不够——它不自动清除 setTimeout 或 addEventListener。这时要用 onScopeDispose 补齐:
- 在
scope.run内调用onScopeDispose(() => { ... }),注册清理函数 - 当
scope.stop()执行时,这些函数会自动被调用 - 例如:
const timer = setTimeout(...); onScopeDispose(() => clearTimeout(timer))
与组件生命周期对齐的推荐写法
在组件中使用时,最稳妥的做法是绑定到标准生命周期钩子:
- 在
onMounted或setup开头创建 scope 并运行逻辑 - 在
onUnmounted中调用scope.stop() - 这样既利用了 Vue 组件卸载机制,又保留了显式控制权,避免依赖隐式行为


















