标准答案

  1. Vue 的 watch、watchEffect、computed 等都会创建响应式 effect,组件 setup 中创建的 effect 通常会绑定到组件实例并在卸载时停止。
  2. effectScope 可以手动创建一个副作用作用域,把多个 watch、watchEffect 等集中收集起来。
  3. 调用 scope.stop() 后,作用域里的副作用会统一停止,适合 composable、插件或组件外状态模块管理清理。
  4. 如果响应式副作用创建在组件生命周期之外,就不能默认依赖组件卸载自动清理。
  5. effectScope 解决的是响应式副作用清理,不会自动取消 fetch、移除 DOM 事件或清掉定时器,这些仍然要单独处理。

题目解析

这道题要区分组件内自动清理和组件外手动清理。很多内存泄漏来自把 watch 放进全局模块后没有 stop。

Composable 如果只在组件 setup 中调用,通常可以依赖组件卸载;如果 composable 自己创建独立作用域或服务单例,就要暴露 stop 或内部管理生命周期。

effectScope 常和 onScopeDispose 配合使用,让调用者所在的作用域销毁时自动执行清理逻辑。

代码示例

下面的作用域可以统一停止内部 watchEffect。

TypeScript
const scope = effectScope()

scope.run(() => {
  watchEffect(() => {
    console.log(userStore.currentUser)
  })
})

function disposeUserWatcher() {
  scope.stop()
}

常见误区

  • 认为所有 watch 都会自动清理,忽略组件外创建的副作用。
  • 用 effectScope 后以为网络请求、事件监听和定时器也会自动取消。
  • 在 composable 中创建长期副作用,但没有暴露停止方式,也没有绑定当前 scope。

作者信息