effectscope 是 vue 3.2+ 用于统一管理响应式副作用生命周期的工具,核心解决“谁来清理”问题;需显式创建、运行和停止,支持嵌套、detached 独立作用域及 onscopedispose 自动清理。

Vue 3.2+ 引入的 effectScope 是一个轻量但关键的生命周期管理工具,核心作用不是增强响应式,而是解决“谁来清理”的问题——尤其当响应式副作用(如 watch、computed、watchEffect)脱离组件上下文时。
基础用法:创建、注入、停止
所有副作用必须显式注册进作用域才受控,不能靠“自动捕获”:
- 调用
effectScope()创建一个作用域实例(此时它什么也不做) - 用
scope.run(() => { ... })执行回调,在其中定义watch、computed等——这些会自动归属该 scope - 调用
scope.stop()一次性释放所有已注册的响应式副作用和依赖关系
例如:
const scope = effectScope()scope.run(() => { const data = ref(null) watch(source, v => data.value = v) const doubled = computed(() => data.value * 2)})// …… 任意时机调用scope.stop() // watch 停止监听,computed 不再更新,内存可回收
组合式函数中封装自销毁逻辑
在 useXxx 函数里创建 scope,让副作用“自带销毁能力”,调用方无需关心内部细节:
- 函数内部创建
effectScope(),并在run中定义响应式逻辑和清理项 - 用
onScopeDispose注册非响应式资源的清理(如clearInterval、removeEventListener) - 可选择返回一个
stop方法,或直接在onUnmounted/ 条件判断中调用scope.stop()
例如轮询 Hook:
export function usePolling(url, interval = 5000) { const scope = effectScope() const data = ref(null) scope.run(() => { const timer = setInterval(async () => { data.value = await (await fetch(url)).json() }, interval) onScopeDispose(() => clearInterval(timer)) watch(data, console.log) }) return { data, stop: () => scope.stop() }}
嵌套与独立作用域的控制逻辑
作用域默认形成树状结构,生命周期天然联动:
- 子 scope 不传参创建(
effectScope()),会自动挂载到当前活跃父 scope 的scopes数组中;父stop()时子自动停止 - 传
true创建 detached 作用域(effectScope(true)),完全独立,不注册到父 scope,适合跨组件共享或长期驻留逻辑(如全局消息总线、后台同步服务)
注意:detached 作用域不会被任何外部 stop() 影响,必须由你主动调用其自身的 stop()。
与组件生命周期对齐的两种方式
虽然 effectScope 是手动 API,但它能无缝融入 Vue 生命周期流程:
- 显式绑定:在
onMounted中调用scope.run(),在onUnmounted中调用scope.stop(),行为与组件一致 - 隐式委托:使用
onScopeDispose—— 它会在当前活跃作用域停止时自动执行,无论这个作用域是组件隐式创建的,还是你手动创建的
后者更通用,尤其适合封装在 Composable 中,不强制依赖组件钩子。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










