Vue3 Watch 完全指南:深度监听与性能优化

一、核心概念:Watch 的作用

Watch 用于监听响应式数据的变化并执行副作用操作。与 Computed 不同,Watch 不返回新值,而是响应变化。

javascript

复制代码
import { watch, ref } from 'vue'

const count = ref(0)

watch(count, (newVal, oldVal) => {
  console.log(`从 ${oldVal} 变为 ${newVal}`)
})

二、Reactive vs Ref:关键差异

1. Reactive 对象:默认深度监听

javascript

复制代码
import { reactive, watch } from 'vue'

const user = reactive({ name: '张三', age: 20 })

// ✅ 默认深度监听,修改属性会触发
watch(user, () => {
  console.log('user变化了')  // 修改 user.name 会触发
})

// 等价于显式声明 deep
watch(user, () => {}, { deep: true })

2. Ref 对象:需要显式深度监听

javascript

复制代码
import { ref, watch } from 'vue'

const user = ref({ name: '张三', age: 20 })

// ❌ 修改属性不会触发(只监听引用变化)
watch(user, () => {
  console.log('不会触发')  // user.value.name = '李四' 不会触发
})

// ✅ 需要显式声明 deep
watch(user, () => {
  console.log('会触发')  // 修改属性会触发
}, { deep: true })

三、深度监听的性能问题

深度监听会递归遍历对象的所有属性,性能开销大。

javascript

复制代码
// ❌ 不推荐:深度监听大型对象
const largeObj = reactive({ /* 大量嵌套数据 */ })
watch(largeObj, callback, { deep: true }) // 性能差

// ✅ 推荐:监听特定属性
watch(() => largeObj.importantProp, callback)

// ✅ 推荐:监听多个特定属性
watch(
  () => [largeObj.prop1, largeObj.prop2],
  callback
)

四、实用配置选项

1. immediate:立即执行

javascript

复制代码
const count = ref(0)

watch(count, callback, { 
  immediate: true // 立即执行一次回调
})

2. flush:控制回调时机

javascript

复制代码
watch(source, callback, {
  flush: 'post' // DOM更新后执行,适合操作DOM
})

五、新旧值的陷阱

深度监听时,新旧值引用相同!

javascript

复制代码
const obj = reactive({ a: 1 })

watch(obj, (newVal, oldVal) => {
  console.log(newVal === oldVal) // true!同一个对象
}, { deep: true })

// 解决方案:手动创建副本
watch(
  () => ({ ...obj }),
  (newVal, oldVal) => {
    console.log(newVal === oldVal) // false
  },
  { deep: true }
)

六、最佳实践总结

  1. 监听选择

    • 基本类型:watch(refValue, callback)

    • Reactive对象:watch(reactiveObj, callback)(默认深度)

    • Ref对象:watch(refObj, callback, { deep: true })

  2. 性能优化

    javascript

    复制代码
    // ❌ 避免深度监听大型对象
    watch(largeObj, callback, { deep: true })
    
    // ✅ 监听特定属性
    watch(() => obj.importantField, callback)
    
    // ✅ 计算属性+监听组合
    const importantData = computed(() => obj.a + obj.b)
    watch(importantData, callback)
  3. 清理副作用

    javascript

    复制代码
    const stop = watch(source, callback)
    
    // 组件卸载时清理
    onUnmounted(() => {
      stop()
    })
  4. 使用 watchEffect(自动依赖追踪)

    javascript

    复制代码
    watchEffect(() => {
      // 自动追踪使用的响应式数据
      console.log(obj.name, obj.age)
    })

七、核心要点速记

  • Reactive默认深度,Ref需要显式声明deep

  • 深度监听有性能开销,尽量监听特定属性

  • 深度监听的新旧值是同一引用

  • 合理使用immediate和flush选项

  • 记得清理不再需要的监听器

选择正确的监听策略,可以让你的Vue应用既保持响应性,又拥有优秀的性能表现。

相关推荐
CoovallyAIHub1 分钟前
用 AI 做 PPT 被辞退,法院判公司赔:员工贴进对话框的数据,到底谁负责?
前端·agent
fruge22 分钟前
SSH、RDP、VNC不必各开一个客户端:Next Terminal用Web入口统一管理远程资产和会话记录
运维·前端·ssh
honkun639 分钟前
vue 下拉树组件 vxe-table-select 实现分页多选
前端·javascript·vue.js
大熊程序猿1 小时前
用 ASP.NET Core + SignalR 做一个带实时对战房间的打字练习平台
javascript
OpsEye1 小时前
大量无效 Token 消耗,是很多企业被忽略的隐形成本
javascript·ai编程
用户621007587021 小时前
Web BIM 开发实践:如何将构件选择、属性查询接入业务系统?
前端
羲云1 小时前
AI 分站搭完就能发链接?上线前先过这 5 关
前端
葡萄城技术团队1 小时前
一个 F4 快捷键,为什么能决定 Web 表格是否像 Excel?
前端
王川7081 小时前
商协会后台前端的模块聚合实践
前端·后端