Vue 3 的响应式系统是其核心优势之一,而 watch 是处理响应式数据变化的"瑞士军刀"。相比于 watchEffect 的"自动追踪",watch 提供了更精确的控制力,允许你指定监听哪些数据,并区分"旧值"与"新值"。
这篇文章将带你深入理解 Vue 3 中的 watch,涵盖基础用法、高级配置以及与 watchEffect 的对比。
🧐 什么是 watch?
在 Vue 3 的组合式 API 中,watch 是一个用于观察和响应响应式状态变化 的 API。它类似于 Vue 2 中的 watch 选项,但在组合式 API 中更加灵活和强大。
核心特点:
- 惰性执行 :
watch在创建时不会立即执行回调,只有当监听的数据发生变化时才会执行(除非配置immediate: true)。 - 精准控制:你可以明确指定监听哪个或哪些数据源。
- 获取旧值:你可以很方便地获取到变化前的旧值和变化后的新值。
🚀 基础用法
在使用 watch 之前,需要先从 Vue 中导入它:
javascript
import { watch } from 'vue'
1. 监听单个数据源 (Ref)
最常见的情况是监听一个 ref。
vue
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
// 监听 count
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变成了 ${newVal}`)
})
// 点击按钮时触发
const increment = () => {
count.value++
}
</script>
<template>
<button @click="increment">Count: {{ count }}</button>
</template>
2. 监听响应式对象的属性 (Getter 函数)
如果你想监听 reactive 对象的某个属性,或者监听一个计算属性,你需要传入一个getter 函数。
vue
<script setup>
import { reactive, watch } from 'vue'
const state = reactive({
name: 'Alice',
age: 25
})
// 监听 state.name
watch(
() => state.name,
(newName, oldName) => {
console.log(`名字从 ${oldName} 改为 ${newName}`)
}
)
</script>
注意: 这里的
() => state.name是一个函数,watch会执行这个函数来获取要监听的值。
⚙️ 监听多个数据源
你可以通过传入一个数组来同时监听多个源。回调函数接收的参数也将是一个数组,分别对应新值和旧值。
vue
<script setup>
import { ref, watch } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
watch(
[firstName, lastName],
([newFirst, newLast], [oldFirst, oldLast]) => {
console.log(`${oldFirst} ${oldLast} -> ${newFirst} ${newLast}`)
}
)
</script>
📦 深度监听与立即执行
watch 接受第三个参数------一个配置选项对象。
1. 深度监听
默认情况下,watch 是浅层的。这意味着如果你监听一个响应式对象,直接修改其嵌套属性可能不会触发回调(取决于你监听的是整个对象还是特定属性)。
使用 deep: true 可以强制深度遍历,监听对象内部所有层级的变化。
javascript
watch(
() => state, // 监听整个对象
(newState, oldState) => {
// 即使是 state.profile.address 变了,这里也会触发
},
{ deep: true }
)
2. 立即执行
使用 immediate: true,回调函数会在创建监听器时立即执行一次。
javascript
watch(
() => searchQuery.value,
(query) => {
// 页面加载时会立即执行一次,无需等待 query 变化
fetchResults(query)
},
{ immediate: true }
)
🛑 停止监听
watch 函数会返回一个 stop 函数。调用这个函数可以停止监听,防止内存泄漏或不必要的计算。
vue
<script setup>
import { ref, watch } from 'vue'
const counter = ref(0)
const stopWatch = watch(counter, (newVal) => {
if (newVal > 10) {
console.log('超过10了,停止监听')
stopWatch() // 停止监听
}
})
</script>
⚖️ watch 与 watchEffect 的区别
初学者常混淆 watch 和 watchEffect,它们的主要区别如下:
| 特性 | watch |
watchEffect |
|---|---|---|
| 数据源 | 需要明确指定监听源 | 自动追踪副作用期间访问的响应式属性 |
| 执行时机 | 默认惰性执行 (变化时触发) | 默认立即执行 (创建时触发) |
| 旧值/新值 | 容易获取 | 需要手动维护变量来比较 |
| 适用场景 | 执行数据变更的副作用 (如 API 调用) | 简单的副作用同步 (如更新 DOM) |
何时使用 watch?
当你需要根据某个特定状态的变化来执行异步操作或开销较大的操作时(例如:搜索建议、表单验证)。
📝 总结
watch 是 Vue 3 中处理响应式数据变化逻辑的基石。通过掌握以下几点,你可以更高效地编写 Vue 应用:
- 监听 Ref:直接传入 ref 变量。
- 监听 Reactive 属性 :传入 getter 函数
() => obj.prop。 - 配置项 :善用
deep和immediate。 - 清理副作用 :记得在适当的时候调用
stop函数。
希望这篇文章能帮助你更好地理解和使用 Vue 3 的 watch!