Vue3 中的 watch 和 watchEffect:如何优雅地监听数据变化

文章目录


前言

在 Vue3 中,Composition API 引入了两个新的函数:watch 和 watchEffect,用于观察响应式数据的变化并执行副作用。它们有什么区别?如何在项目中正确使用?本文将结合示例详细讲解


一、 watch

watch用于监听一个或多个响应式数据源,并在数据源变化时执行回调函数。

1.基本用法

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

const count = ref(0)

// 监听单个 ref
watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变为 ${newValue}`)
})

2.监听多个数据源

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

// 监听多个 ref
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
  console.log(`count 从 ${oldCount} 变为 ${newCount}`)
  console.log(`name 从 ${oldName} 变为 ${newName}`)
})

3. 监听 reactive 对象

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

const state = reactive({ count: 0, name: 'Alice' })

// 监听整个 reactive 对象
watch(
  () => state, 
  (newValue, oldValue) => {
    // 注意:newValue 和 oldValue 是同一个对象,因为引用相同
    console.log('state 变化了', newValue.count)
  },
  { deep: true } // 需要深度监听
)

// 更好的方式:监听单个属性
watch(
  () => state.count,
  (newCount, oldCount) => {
    console.log(`state.count 从 ${oldCount} 变为 ${newCount}`)
  }
)

4.立即执行

默认情况下,watch 是惰性的,即第一次不会执行。可以通过配置 immediate: true 来立即执行。

javascript 复制代码
watch(
  count,
  (newValue, oldValue) => {
    console.log(`count 是 ${newValue}`)
  },
  { immediate: true }
)

5.停止监听

watch 会返回一个停止函数,调用它可以停止监听。

javascript 复制代码
const stop = watch(count, (newValue, oldValue) => {
  // ...
})

// 停止监听
stop()

二、watchEffect

watchEffect 会立即执行传入的函数,同时响应式地追踪其依赖,并在依赖变更时重新运行该函数。

1.基本用法

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

const count = ref(0)

watchEffect(() => {
  console.log(`count 的值是: ${count.value}`)
})

2.自动追踪依赖

watchEffect 会自动追踪函数内部使用的响应式变量,无需显式指定监听源。

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

watchEffect(() => {
  console.log(`count: ${count.value}, name: ${name.value}`)
  // 会自动追踪 count 和 name
})

3.停止监听

与 watch 一样,watchEffect 也返回一个停止函数。

javascript 复制代码
const stop = watchEffect(() => {
  // ...
})

// 停止监听
stop()

4.清除副作用

有时副作用函数会执行一些异步操作,在重新执行或停止时,我们需要清除这些异步操作。watchEffect 提供了一个 onInvalidate 函数,用于注册清理回调。

javascript 复制代码
watchEffect((onInvalidate) => {
  const timer = setTimeout(() => {
    console.log('异步操作', count.value)
  }, 1000)

  onInvalidate(() => {
    clearTimeout(timer)
  })
})

三、watch 与 watchEffect 的区别

特性 watch watchEffect
执行时机 默认惰性,不会立即执行,需要 immediate: true 立即执行
依赖追踪 需要显式指定监听源 自动追踪函数内部使用的响应式变量
旧值 可以获取旧值 无法获取旧值
使用场景 需要知道旧值和新值,或需要精确控制监听源 不需要旧值,且依赖多个数据源,希望自动追踪

四、选择指南

使用 watch 当:

  • 需要知道变化前的值(旧值)
  • 只需要监听特定数据
  • 需要控制监听时机(惰性执行)

使用 watchEffect 当:

  • 依赖多个数据,不想手动声明
  • 需要立即执行副作用
  • 执行的操作与多个响应式数据相关

记住这个简单的选择原则:

  • 需要旧值或精确控制?用 watch
  • 立即执行且依赖多个数据?用 watchEffect

五、注意事项

  • 避免在 watch 和 watchEffect 中修改依赖的数据,以免造成无限循环。
  • 对于监听多个数据源,如果希望同步执行,可以使用 watch 的数组形式;如果依赖自动追踪,使用 watchEffect。
  • 在组件卸载时,watch 和 watchEffect 会自动停止,除非你设置了 { flush: 'post' } 等选项。

总结

watch 和 watchEffect 都是 Vue3 中强大的响应式工具。watch 更适合需要明确监听源和旧值的场景,而 watchEffect 则更适合依赖多个数据源且不需要旧值的场景。

相关推荐
小月鸭19 小时前
理解预处理器(Sass/Less)
前端
AI3D_WebEngineer20 小时前
企业级业务平台项目设计、架构、业务全解之组件库篇
前端·javascript·vue
charlie11451419120 小时前
从零开始理解 CSS:让网页“活”起来的语言2
前端·css·笔记·学习·选择器·样式表·原生
浪裡遊20 小时前
Next.js路由系统
开发语言·前端·javascript·react.js·node.js·js
mapbar_front20 小时前
职场中的顶级能力—服务意识
前端
STUPID MAN21 小时前
Linux使用tomcat发布vue打包的dist或html
linux·vue.js·tomcat·html
尽兴-21 小时前
[特殊字符] 微前端部署实战:Nginx 配置 HTTPS 与 CORS 跨域解决方案(示例版)
前端·nginx·https·跨域·cors·chrom
JIngJaneIL1 天前
助农惠农服务平台|助农服务系统|基于SprinBoot+vue的助农服务系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·助农惠农服务平台
云外天ノ☼1 天前
待办事项全栈实现:Vue3 + Node.js (Koa) + MySQL深度整合,构建生产级任务管理系统的技术实践
前端·数据库·vue.js·mysql·vue3·koa·jwt认证
gihigo19981 天前
使用JavaScript和Node.js构建简单的RESTful API
javascript·node.js·restful