watcheffect依靠vue 3的reactiveeffect机制自动收集依赖:执行时通过proxy getter拦截读取的响应式数据(如ref.value、reactive属性),将其标记为依赖;变化时触发setter并重跑函数,动态更新依赖集合;组件卸载时自动停止。

watchEffect 能自动盯住你用到的响应式数据,靠的不是魔法,而是 Vue 3 响应式系统底层的 ReactiveEffect 机制——它在函数执行时悄悄记下“谁被读了”,后续一变就重跑。
依赖怎么被悄悄收集的?
你传给 watchEffect 的函数,Vue 会立刻执行一次。执行过程中,只要访问了 ref.value、reactive 对象的属性 或 computed 的值,Vue 就通过 Proxy 的 get 拦截器捕获这次读取,并把当前正在运行的副作用函数记为该响应式数据的依赖。
- 比如函数里写了
searchTerm.value和user.profile.city,这两个就是依赖项 - 如果用了
if (showDetails) { user.address.zip },只有showDetails为真时,user.address.zip才会被追踪 - 没进分支的读取、没执行到的代码,不会建立依赖
变化时怎么触发重执行?
当某个被追踪的响应式值被修改(触发 setter),Vue 就知道:这个值的所有依赖函数都该更新了。于是它会重新调用 watchEffect 回调,并在新执行中再次收集依赖——旧依赖自动丢弃,新依赖动态建立。
- 整个过程无需你手动列数组,也不用担心深层字段漏监听(但注意:必须显式读取
user.a.b,只读user.a不会追踪b的变化) - 组件卸载时,watchEffect 默认自动停止,避免内存泄漏
为什么不用手动写依赖列表?
因为 watchEffect 的核心实现其实只有一行关键逻辑:doWatch(effect, null, options)。传入 null 作为第二个参数,就告诉 Vue:“别等我指定监听谁,你直接去跑函数,边跑边记。”
- 这和 watch 的工作模式完全不同——watch 需要你明确告诉它“监听什么”,watchEffect 是“执行中发现什么,就盯什么”
- 这种设计让代码更贴近真实逻辑流:参数变了 → 请求发了 → 界面更新了,中间没有配置胶水











