持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
前言
watch 是我们最常用的 api 之一,能够监听对象的修改,今天主要看看 watch 的源码是如何实现的。
使用
如果只监听一个数据源
// 监听 state.count 的 getter 方法,触发getter时触发watch
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 监听 ref 时,直接把 ref 传入
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
当然,有时候我们需要监听多个数据,如果每监听一个数据就写一个 watch 的话,会使代码变得更臃肿,所以 watch 也可以一次性监听 多个数据。
// 全部监听 ref
const ref1 = ref(0)
const ref2 = ref(0)
watch([ref1, ref2], ([ref1NewValue, ref2NewValue], [ref1OldValue, ref2OldValue]) => {
console.log('ref1:', ref1NewValue, ref1OldValue);
console.log('ref2:', ref2NewValue, ref2OldValue);
})
// ref 和 reactive可以一起监听
const ref1 = ref(0)
const state = reactive({ count: 0 })
watch([ref1, () => state.count], ([ref1NewValue, ref2NewValue], [ref1OldValue, ref2OldValue]) => {
/** */
})
监听多个数据源时,回调函数回接收两个数组参数,第一个时新值集合,第二个时旧值集合,其中值的顺序和我们监听列表的顺序一致。
源码
学会了如何使用 watch ,我们再来看下 watch 的源码。watch 的源码位置在 packages/runtime-core/src/apiWatch.ts
// packages/runtime-core/src/apiWatch.ts
export function watch<T = any, Immediate extends Readonly<boolean> = false>(
source: T | WatchSource<T>,
cb: any,
options?: WatchOptions<Immediate>
): WatchStopHandle {
return doWatch(source as any, cb, options)
}
可以看到, watch 接收3个参数,分别是监控源、回调函数、配置选项,然后直接反回 doWatch 的结果。
doWatch 函数的代码比较长,我们一部分一部分看。首先从声明看起。
function doWatch(
source: WatchSource | WatchSource[] | WatchEffect | object,
cb: WatchCallback | null,
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
)
可以看到接收的参数与 watch 一致,监控源source,回调函数,配置参数。配置参数可以传5个
- immediate 立即执行一次回调
- deep 是否尝试检查深度嵌套对象或数组中的 property 变化
- 如果需要在组件更新后重新运行侦听器副作用,我们可以设置 flush 为 post,flush 选项还接受
sync,这将强制效果始终同步触发。然而这是低效的,应该很少需要。 - 还有就是侦听器调试
onTrack和onTrigger方法,它们只在开发环境生效,其中-onTrack将在响应式 property 或 ref 作为依赖项被追踪时被调用。onTrigger将在依赖项变更导致副作用被触发时被调用。
这些就是 watch 的所以可选配置项。
小结
这节学了如何使用watch 方法,和一部分源码,下一篇我们再继续深入研究watch的源码。