文章目录
- 前言
- [一、 watch](#一、 watch)
- 二、watchEffect
- [三、watch 与 watchEffect 的区别](#三、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 则更适合依赖多个数据源且不需要旧值的场景。