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应用既保持响应性,又拥有优秀的性能表现。

相关推荐
sugar__salt2 小时前
Vue3 表单双向绑定与响应式核心 API 技术详解
前端·javascript·vue.js
郝亚军2 小时前
使用Vue 3和Nginx打包和部署Vue.js项目的一般步骤
前端·vue.js·nginx
SmartBoyW2 小时前
CSS弹性布局(Flexbox)学习笔记:从零开始搞懂弹性布局
前端·javascript
用户69371750013842 小时前
从代码生产者到 AI 协作者:软件工程师的角色重构
android·前端·后端
嘟嘟07172 小时前
搞懂 useState 从原生 DOM 到 React 惰性初始化的完整链路
前端·react.js·编程语言
牧艺2 小时前
cos-design RippleWater & SmokeFog:水面涟漪与烟雾雾气怎么做
前端·canvas·视觉设计
用户938515635073 小时前
写了这么久 useState,你真的知道它在干什么吗?
前端·javascript
慢功夫3 小时前
💡第七篇:VSCode语言服务中,代码跳转和诊断是怎么做的?
前端·visual studio code
Csvn3 小时前
✨ TypeScript `satisfies` 操作符实战——5 个让代码更「聪明」的生产场景
前端
Healer9183 小时前
vue3页面缓存-keepAlive
前端