effect 返回的 runner 函数既是手动执行入口,也是 stop 控制句柄;stop 永久解除依赖追踪、清空 deps 并设 active 为 false,不可恢复;watchEffect 的 stop 行为与之完全一致。

effect 返回一个函数,调用它就能停止该副作用的后续响应。这个返回值就是 stop 方法本身,不是额外封装的工具,而是 effect 创建时自动生成的控制句柄。
effect 的返回值本质是 runner 函数
effect 接收一个副作用函数,内部会创建 ReactiveEffect 实例并执行一次。它最终返回的是一个绑定到该实例的 run 方法(常称 runner),这个函数既能手动触发执行,也携带了对实例的引用,用于后续控制。
- 首次调用 effect 后得到的值,就是一个可执行、可停止的函数
- runner.effect 指向对应的 ReactiveEffect 实例(Vue 内部实现中挂载)
- 调用 runner() 等价于重新运行该副作用,与响应式变化无关,纯手动触发
stop 方法的作用是切断响应链
stop 不是暂停,而是永久性解除依赖追踪关系。它会清空该 effect 所有已收集的依赖(deps),把 active 设为 false,并释放 track/trigger 关联,让 GC 可以回收相关资源。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 调用 stop() 后,即使依赖数据再变化,该 effect 也不会再次执行
- 已注册的 computed 或 watch 不会更新,watchEffect 不再响应,但当前正在运行的回调仍会完成
- 多次调用 stop() 无副作用,但无法“恢复”或“重启”——effect 不支持热重连
和 watchEffect 的 stop 返回值是一致的
watchEffect 也返回一个 stop 函数,行为逻辑与 effect 完全相同:都是终止当前副作用的响应式监听。区别只在于使用场景和依赖收集方式。
立即学习“前端免费学习笔记(深入)”;
- watchEffect 自动收集内部读取的响应式数据,无需显式声明依赖
- effect 更底层,适合需要精细控制或调试依赖的场合(如源码学习、自定义响应式逻辑)
- 两者返回的 stop 函数都可直接传给 onBeforeUnmount,实现组件卸载时自动清理
实际使用中的关键提醒
别把 effect 当作普通工具函数随意调用。它不被 Vue 官方推荐在业务代码中直接使用,因为容易引发无限循环或内存泄漏。
- 业务逻辑优先用 watch、watchEffect、computed;effect 主要用于框架开发或深度定制
- 如果用了 effect,务必保存好返回的 stop 函数,并在合适时机调用(比如组件 unmounted 或弹窗关闭)
- effectScope.stop() 是更高层的批量管理方式,适用于聚合多个 effect 的场景,和单个 effect.stop() 互补而非替代

















