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

相关推荐
摘星编程3 小时前
React Native + OpenHarmony:Spinner旋转加载器
javascript·react native·react.js
We་ct3 小时前
LeetCode 205. 同构字符串:解题思路+代码优化全解析
前端·算法·leetcode·typescript
2301_812731413 小时前
CSS3笔记
前端·笔记·css3
ziblog3 小时前
CSS3白云飘动动画特效
前端·css·css3
越努力越幸运5083 小时前
CSS3学习之网格布局grid
前端·学习·css3
半斤鸡胗3 小时前
css3基础
前端·css
ziblog3 小时前
CSS3创意精美页面过渡动画效果
前端·css·css3
akangznl3 小时前
第四章 初识css3
前端·css·css3·html5
会豪3 小时前
深入理解 CSS3 滤镜(filter):从基础到实战进阶
前端·css·css3
头顶一只喵喵3 小时前
CSS3进阶知识:CSS3盒子模型,box-sizing:content-box和box-sizing:border-box的讲解
前端·css·css3