vue watch 侦听器的权衡.md
# vue watch 侦听器的权衡 > 记录实习时一次发生的bug 在 Vue 3 中,`watch` 对数组、对象等‘引用类型’默认只比较**引用地址**: ```js watch( () => props.list, (val) => { // TODO } ) ``` 对 list 的监听只是地址,如:当父组件用 `splice` 原地修改数组时: > splice:在当前数组的基础上进行更改 > > 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/splice ```js // 父组件 list.value.splice(idx, 1) // 原地删除,引用不变 ``` 子组件的 `watch` **不会触发** ——地址没变,不会触发更改。子组件仍内部保留旧数据,存在潜在的 bug ## 修复 #### 方案一:深层侦听 `{ deep: true }` ```js watch( () => props.list, (val) => { // TODO }, { deep: true } // 深度侦听 ) ``` 优缺: - ✅ 能解决问题 - ❌ 性能开销:递归遍历每个属性建立依赖,每次嵌套值变化都触发 - ❌ 语义错位:若只关心增删,但深层侦听会对每个状态的变化进行侦听,如: `item.status` 变化也要触发一次深拷贝,因此若只考虑增删,使用 deep 开销太大 #### 方案二: filter 返回新引用 filter 会返回新的数组,此时地址发生了改变 ```js // 父组件 list.value = list.value.filter((_, i) => i !== idx) // 新数组,新引用 ``` - ✅ 地址变了 →watch 自然触发 若只是对增删进行处理,建议将 `splice` 替换为`filter` ,只用一行代码,避免了 `deep: true` 带来的所有副作用
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与