watchEffect 通过自动追踪实际读取的响应式路径实现精准监听,无需 deep: true;应直接访问具体字段(如 user.profile?.name),避免仅读取对象引用;多个字段可共用一个 watchEffect;需新旧值对比时应改用 watch。

watchEffect 本身不提供“深度监听”开关,它靠自动追踪你代码里实际读取的响应式路径来工作。想精准追踪深层嵌套属性,关键不是让它“变深”,而是确保你在回调里真正“访问”到了那个具体字段——只要访问了,它就自动追踪,无需 deep: true。
只读取你要关注的字段路径
watchEffect 会扫描你传入函数中所有 被读取(get)的响应式属性。所以别写整个对象,直接点到你要的值:
- ✅ 正确:访问具体字段,自动建立精准依赖
watchEffect(() => console.log(user.profile?.name))
→ 只响应 user.profile.name 的变化,user.profile.age 或 user.status 改了不会触发 - ❌ 错误:只读对象引用,无法捕获内部变更
watchEffect(() => console.log(user.profile))
→ profile 对象引用没变,内部属性改了也不会触发
确保中间层级都是响应式对象
可选链(?.)不影响依赖收集,但前提是每一步都落在响应式代理上:
- user 是 reactive 或 ref 包裹的 → ✅
- user.profile 是初始化时就存在的响应式对象(比如 reactive({ name: '' }))→ ✅
- 如果 profile 是后期动态添加的普通对象(如 user.profile = { name: '' }),那 name 就不是响应式的 → ❌
补救方式:用 ref 包裹深层对象,或初始化时定义完整结构。
多个嵌套字段一起追踪,用逗号分隔读取
不需要写多个 watchEffect,把多个字段读取写在同一个函数里即可:
watchEffect(() => {<br> console.log('name:', user.profile?.name)<br> console.log('city:', user.address?.city)<br> console.log('status:', user.status)<br>})- 任意一个字段变化,整个函数都会重执行
需要新旧值对比?换用 watch
watchEffect 不提供 oldValue 和 newValue。如果你要判断 “是从 A 变成 B”,或者做防抖、节流、仅首次变更才执行等逻辑,应该用 watch:
watch(() => user.profile?.name, (newVal, oldVal) => {<br> if (newVal !== oldVal) doSomething()<br>})- 这样既能精准监听,又能拿到前后值,语义更清晰


















