Vue3中,我的Watch为什么总监听不到数据?

前言

vue3中, watch使用 watch(()=>xxx,v=>{})或者watch(xxx,val=>{})时, 总是遇到函数写法的watch监听,数据改变后没有监听到数据改变;非函数的写法反而可以监听到。

在 Vue 3 中,这两种 watch 的使用方式确实有重要区别:

1. 语法区别

javascript 复制代码
// 方式一:使用函数
watch(() => obj.property, (val) => {
  console.log('值变化了:', val)
})

// 方式二:直接监听响应式对象
watch(obj, (val) => {
  console.log('对象变化了:', val)
})

2. 关键区别

方式一: 函数 () => xxx

  • 监听特定属性 :只追踪 obj.property 这个具体的值
  • 浅层监听 :只有当 obj.property 的值本身发生变化时才触发
  • 不追踪对象引用 :不关心整个 obj 对象的变化

方式二:直接监听响应式对象 xxx

  • 监听整个对象:追踪对象的所有属性变化
  • 深层监听:默认深度监听对象内部所有嵌套属性的变化
  • 追踪引用变化:也会监听对象本身的重新赋值

3. 为什么有时候 "函数的写法监听不到?"

情况一:嵌套对象属性变化

javascript 复制代码
const obj = reactive({ 
  nested: { 
    value: 1 
  } 
})

// ❌ 监听不到 nested.value 的变化
watch(() => obj.nested, (val) => {
  console.log('不会触发')
})

// ✅ 需要深度监听
watch(() => obj.nested, (val) => {
  console.log('会触发')
}, { deep: true })

// ✅ 或监听具体属性
watch(() => obj.nested.value, (val) => {
  console.log('会触发')
})

情况二:数组操作

javascript 复制代码
const arr = reactive([1, 2, 3])

// ❌ 监听不到 push/pop 等操作
watch(() => arr.length, (val) => {
  console.log('可能不会触发')
})

// ✅ 直接监听数组
watch(arr, (val) => {
  console.log('会触发')
})

情况三:解构丢失响应性

javascript 复制代码
const obj = reactive({ x: 1, y: 2 })

// ❌ 解构会丢失响应性
const { x } = obj
watch(x, (val) => { }) // 无效

// ✅ 使用 getter 函数
watch(() => obj.x, (val) => {
  console.log('会触发')
})

4. 实践建议

使用函数 () => xxx 的场景:

  • 监听基本类型值(string, number, boolean)
  • 监听对象的特定属性
  • 需要计算或组合的依赖
  • 避免不必要的深度监听
javascript 复制代码
// 监听特定属性
watch(() => user.name, (name) => {
  console.log('用户名变化:', name)
})

// 监听计算值
watch(() => x.value + y.value, (sum) => {
  console.log('和变化:', sum)
})

使用直接监听 xxx 的场景:

  • 需要监听对象所有变化
  • 监听数组变化
  • 需要深度监听嵌套对象
  • 监听引用变化
javascript 复制代码
// 监听整个响应式对象
watch(state, (newState) => {
  console.log('状态变化:', newState)
}, { deep: true })

// 监听数组
watch(items, (newItems) => {
  console.log('列表变化:', newItems)
})

5. 注意事项

ref 对象的处理:

javascript 复制代码
const count = ref(0)

// ✅ 正确:直接监听 ref
watch(count, (val) => {
  console.log('count变化:', val)
})

// ✅ 也正确:通过 .value 监听
watch(() => count.value, (val) => {
  console.log('count变化:', val)
})

reactive 对象的处理:

javascript 复制代码
const state = reactive({ count: 0 })

// ✅ 推荐:使用 getter 监听特定属性
watch(() => state.count, (val) => {
  console.log('count变化:', val)
})

// ⚠️ 注意:直接监听 reactive 对象会自动开启深度监听
watch(state, (val) => {
  console.log('state变化:', val) // 任何嵌套属性变化都会触发
})

总结

选择哪种方式主要取决于:

  1. 监听粒度:需要监听整个对象还是特定属性
  2. 性能考虑:避免不必要的深度监听
  3. 数据类型:基本类型用 getter,复杂对象可直接监听
  4. 变化类型:需要监听引用变化还是值变化

当发现监听不到变化时,检查是否是:

  • 嵌套对象属性变化(需要 deep: true
  • 数组方法修改(直接监听数组)
  • 解构导致响应性丢失(使用函数)
相关推荐
灵感__idea5 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea6 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd8 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌8 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈8 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫8 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝8 小时前
svg图片
前端·css·学习·html·css3
橘子编程9 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇9 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧9 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint