Vue3里watchEffect加deep配置到底怎么用?有哪些坑要注意?
很多刚从Vue2转Vue3的开发者,经常会把watch和watchEffect的监听逻辑搞混,尤其是watchEffect的deep配置,网上各种说法都有,有人说watchEffect默认就是深度监听不用开deep,有人说必须开才能监听到深层属性,还有人开了deep之后发现根本不生效,踩了一堆坑,今天我们就把Vue3中watchEffect的deep配置的所有相关问题都讲透,从底层逻辑到实际场景,再到常见踩坑,看完你就不会再用错了。
先搞懂:watchEffect本身默认是不是深度监听?
要搞懂deep配置的作用,首先得理清楚watchEffect的默认监听逻辑,和watch需要显式指定监听源不同,watchEffect的核心逻辑是「自动依赖收集」:它会在首次执行回调函数的时候,记录下所有被访问过的响应式属性,后续只有这些被记录的属性发生变化时,才会重新触发回调。 我们先看一个最基础的例子: ```javascript import { reactive, watchEffect } from 'vue' // 定义一个嵌套的响应式对象 const userInfo = reactive({ name: '张三', age: 25, address: { city: '北京', district: '朝阳区', street: { name: '建国路', number: '88号' } } }) // 定义watchEffect,回调里只用到了name和city两个属性 watchEffect(() => { console.log(`用户信息更新:${userInfo.name} - ${userInfo.address.city}`) }) // 测试1:修改name属性 → 触发回调,输出「用户信息更新:李四 - 北京」 userInfo.name = '李四' // 测试2:修改city属性 → 触发回调,输出「用户信息更新:李四 - 上海」 userInfo.address.city = '上海' // 测试3:修改district属性 → 不会触发回调!因为回调里没有访问过这个属性 userInfo.address.district = '静安区' // 测试4:修改街道门牌号 → 同样不会触发回调 userInfo.address.street.number = '66号' ``` 从这个例子就能看出来,默认情况下watchEffect根本不是深度监听,它只会监听自己回调里实际用到的属性,不管你对象嵌套多少层,没用到的属性就算改上天也不会触发回调,很多人误以为watchEffect默认深度监听,其实是因为他们在回调里隐式访问了对象的所有属性,比如用`JSON.stringify(userInfo)`、`Object.assign({}, userInfo)`这类操作,会遍历对象的所有层级属性,相当于给所有属性都收集了依赖,自然看起来像是“深度监听”了。watchEffect的deep配置到底是解决什么问题的?
既然默认的依赖收集已经能满足大部分场景,那为什么还要加deep配置?核心是解决「不需要明确指定监听属性,只要监听对象任意层级发生变化就要触发回调」的场景。 举个非常典型的业务场景:你做了一个动态表单,表单的字段是后台动态返回的,可能有十几个甚至几十个嵌套字段,你需要每次用户修改任何表单内容,都自动把整个表单数据序列化存到localStorage做草稿,防止页面刷新丢失内容,这种情况下你总不可能把后台可能返回的所有字段都提前写到watchEffect的回调里吧?不仅麻烦,后续后台改字段你还要同步改代码,可维护性极差。 还有一种场景就是对ref包裹的对象的监听,很多人在这里踩过坑: ```javascript import { ref, watchEffect } from 'vue' // 用ref包裹嵌套对象 const userInfo = ref({ name: '张三', address: { city: '北京' } }) // 默认情况下的watchEffect watchEffect(() => { // 这里只访问了ref的value,没有访问内部的任何属性 console.log('用户信息变化', userInfo.value) }) // 测试1:替换整个ref的value → 触发回调,因为ref的value引用变了 userInfo.value = { name: '李四' } // 测试2:修改深层的city属性 → 不会触发回调!因为回调没有访问过city属性,没有收集到对应的依赖 userInfo.value.address.city = '上海' ``` 这个时候deep配置就派上用场了,给watchEffect加上`deep: true`之后,它会对回调里访问到的所有响应式对象/Ref做递归监听,不管你有没有访问深层属性,只要对象的任意层级发生了变化,都会触发回调,我们给上面的例子加上deep配置: ```javascript watchEffect(() => { console.log('用户版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


