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.