Vue3 中 watch 的使用
watch
用于在数据 (监听源) 变化时, 触发某个行为 (调用一个函数), 并获得更新的数据 (附带原有的数据).
相关的 watch
方法有:
watch()
公共方法watchEffect()
自动跟踪源watchPostEffect()
自动跟踪后置执行watchSyncEffect()
自动跟踪实时执行
watch
是最为原始的方法,watchEffect
算是一种优化改进, 会如同 计算属性一样, 自动配置需要跟踪的源. 剩下的*Effect
则是watchEffect
的语法糖 (快捷方法).
1. watch
语法
官方文档: https://cn.vuejs.org/api/reactivity-core.html#watch
基本用法:
const stopHandle = watch(响应式字段 | () => xxx, (newVal, oldVal) => {
// ...
})
当监控的字段发生变化时, 回调函数会被执行. 并将新值, 与旧值作为参数传入, 以供开发者实现具体任务.
补充说明:
- 源可以不是一个字段, 可以是一个数组, 或元组, 也可以是一个
getter
. - 回调函数可以有第三个参数, 用于频繁调用响应时, 取消上一次未完成的任务.
watch
只会监听源的变化.- 要停止监听, 只需要调用其返回的函数, 例如:
stopHandle()
. 同步执行的watch
会自动处理停止, 只有异步定义的watch
才需要手动停止. WatchOptions
定义了附加操作:watch
是惰性执行的, 如果要立即执行, 使用选项immediate: true
- 源是对象时, 默认只会监听表层属性, 如果要递归所有属性, 使用
deep: true
, 但会影响性能 - 回调函数会在 DOM 刷新前进行调用, 如果要在 DOM 刷新后调用, 使用
flush: 'post'
, 若要实时则用'flush: sync'
onTrack
和onTrigger
在调试模式下执行, 用于监视调用过程.
DOM 刷新之前, 意味着此时访问 DOM, 获得的是更新之前的状态.
watch
完整语法:
// 侦听单个来源
function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): StopHandle
// 侦听多个来源
function watch<T>(
sources: WatchSource<T>[],
callback: WatchCallback<T[]>,
options?: WatchOptions
): StopHandle
type WatchCallback<T> = (
value: T,
oldValue: T,
onCleanup: (cleanupFn: () => void) => void
) => void
type WatchSource<T> =
| Ref<T> // ref
| (() => T) // getter
| T extends object
? T
: never // 响应式对象
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // 默认:false
deep?: boolean // 默认:false
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
2. watchEffect
语法
watch
需要设置源, 再定义回调函数, 为了简化, watchEffect
会自动跟踪源, 逻辑上类似于 计算属性的处理方式.
一般用法:
watchEffect(() => {
// ... 使用到的数据会自动绑定称为源, 一旦源发生变化, 就会触发该方法
})
执行上的注意点:
watchEffect
默认是immediate
, 有别于watch
的惰性执行.watchEffect
中或含有异步代码, 仅有同步代码中使用到的依赖会被作为源使用.watchEffect
会自动设定需要跟踪的依赖, 并且默认就是跟踪使用到属性, 不存在需要使用deep
的情况.- 相比较
watch
,watch
控制更清晰, 但需要一个个手动输入;watchEffect
更简洁, 但依赖不那么清晰. watch
不因回调时的代码而影响源,watchEffect
则依赖回调代码中的数据来确定源.- 使用上默认依旧会在 DOM 更新前执行, 如果修改, 使用
flush
选项. 或两个语法糖.
严格定义:
function watchEffect(
effect: (onCleanup: OnCleanup) => void,
options?: WatchEffectOptions
): StopHandle
type OnCleanup = (cleanupFn: () => void) => void
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
type StopHandle = () => void
3. watchPostEffect
和 watchSyncEffect
相当于 flush
分别设置为 post
和 sync
的 watchEffect
.