Vue3源码解析watch函数实例
在Vue3.x中,watch函数作为一个重要的API存在,它能够对一个值进行监测,当这个值发生变化时,就可以执行相关的回调函数。本文将分享一个完整的攻略,来解析Vue3源码中watch函数的实现。
1. watch函数的基本用法
在Vue3.x中,watch函数的基本用法如下:
// 监听一个值
watch(
// 被监听的值的getter函数,以响应式的方式进行监听
() => count,
// 当值发生变化时,执行的回调函数
(newVal, oldVal) => {
console.log(`count由${oldVal}变为${newVal}`)
}
)
基本上,watch函数就是把我们之前在Vue2.x中使用的$watch API包装一下,让其更加灵活,并且可以自由组合使用。
2. watch API的实现
先来看看Vue3源码中是如何实现watch API的。
在packages/reactivity/src
目录下,有一个叫做baseHandlers.ts
的文件,其中定义了一个createGetterInvoker
函数,它的作用是返回一个getter函数,这个getter函数可以直接触发依赖收集。这里我们只关注它是如何实现的:
export function createGetterInvoker(fn) {
const invoker = (...args) => {
return fn(...args)
}
;(invoker as any).__inject__ = true // 用于标记当前函数是一个getter函数
return invoker
}
通过以上代码可以看到,createGetterInvoker
函数的作用是返回一个函数,这个函数会被标记为一个getter函数,以便在后续的代码中识别。
在watch
函数中我们传入了两个参数:第一个参数是要监听的对象,第二个参数是回调函数,具体实现如下:
export function watch(getter: () => any, cb: Function, options?: WatchOptions) {
const fn = () => {
cb(getter(), value)
}
const { lazy, deep, flush, onTrack, onTrigger } = options || {}
const onInvalidate = () => {
runner.effect.stop()
}
const runner = effect(
fn,
lazy
? { lazy: true, scheduler: () => {
if (!runner.isActive) {
runner.activate()
fn()
}
} }
: {
scheduler: () => {
if (!runner.isFlushPending) {
runner.isFlushPending = true
nextTick(runner.flush)
}
}
}
)
if (deep) {
traverse(getter())
}
let value = undefined
if (!lazy) {
value = getter()
// 触发一次回调,以便获取初始的状态
cb(value, undefined)
}
// 保存effect对象,以便在用户手动解绑时使用
const effect = runner.effect
effect.onInvalidate = onInvalidate
...
}
在上面的代码中,实际上是通过effect
函数来进行依赖收集的。effect
函数会返回一个对象,称之为effect对象,它有很多属性和方法,其中最重要的两个属性是deps
和depsCount
,它们用于记录这个effect对象所依赖的响应式对象以及其数量。
在watch
函数中,我们通过effect()
函数创建了一个effect对象,然后在后续的代码中,将我们传入的回调函数作为这个effect对象的fn
属性来执行。
同时,我们还把getter()
函数传入了traverse
函数中,表示要执行一次“深遍历”操作,以便把响应式对象中的所有属性都进行依赖收集。
需要注意的是,我们在代码的开头处用到了patchFlag
和shapeFlag
这两个变量,它们其实是跟Vue3中的虚拟DOM相关的,这里我们不用管它们是如何实现的,只需要知道它们的存在即可。
3. watch函数的用例分析
我们可以通过下面的示例来进一步了解watch函数的用例和实现细节。
// 一个简单的对象
const obj = reactive({ count: 0 })
// 操作对象的count属性
const operateObj = (num) => {
obj.count += num
}
// 监听对象的count属性
watch(
() => obj.count,
(newVal, oldVal) => {
console.log(`count由${oldVal}变为${newVal}`)
}
)
// 改变对象的count属性
operateObj(1)
operateObj(2)
在上述代码中,我们通过reactive
将一个普通的对象变成了响应式对象,然后对其count
属性进行了监听。
然后我们又通过operateObj
函数对count
属性进行了两次修改。由于我们已经对count
属性进行了监听,所以就会执行相关的回调函数,控制台会输出下面的内容:
count由0变为1
count由1变为3
这说明了watch函数的实现逻辑是正确的,并且能够很好地实现对响应式对象的监测。
总结
我们通过分析Vue3源码来了解了watch函数的实现逻辑,以及它在实际应用中的使用方法。在Vue3.x中,watch函数的重要性不言而喻,我们可以通过它来监听一个值,然后在值发生变化时执行相关的业务逻辑,从而提高Vue应用的响应性和可维护性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue3源码解析watch函数实例 - Python技术站