Effect
上一节,我们已经完成reactive的基本逻辑,这一节,我们来创建一个effect,为后面的依赖收集和触发依赖做准备。
单测
下面,就跟着单测一起来了解effect的功能点。
// src/reactivity/test/effect.spec.ts
import {effect} from "../effect"
import {reactive} from "../reactive"
describe("effect", () => {
it("happy path", () => {
// 创建一个响应式对象
const user = reactive({
age: 10
})
// 定义全局变量nextAge
let nextAge;
// 执行effect,接收一个fn作为参数,在函数内部对nextAge进行赋值
effect(() => {
nextAge = user.age + 1
})
// 赋值成功,说明在执行effect的时候会自动执行传入的函数
expect(nextAge).toBe(11)
})
})
同reactive一样,effect也是一个函数,默认接收一个fn作为参数,从单例可以看出当执行effect(fn)的时候,默认会执行里面的fn,这一节,我们就来完成这个简单的功能,至于怎么做到数据同步更改,等我们完成收集依赖和触发依赖。
编码
在这里有一点跟reactive不同,effect模块我们不仅仅是导出一个effect函数,还需要一个公共的类ReactiveEffect,当然你也可以用构造函数来代替它的功能。
// src/reactivity/effect.ts
let activeEffect;
class ReactiveEffect {
private _fn: any
constructor (fn) {
this._fn = fn
}
public run () {
activeEffect = this //将当前实例对象赋值给全局变量activeEffect,在依赖收集的时候有用
this._fn()
}
}
export function effect (fn) {
const _effect = new ReactiveEffect(fn)
_effect.run()
}
上面便是我们这一节要完成的所有代码及功能,看起来很简单,但是却有点不大好理解,为什么要这么写?可以把effect当成一个纽带,当然它更像vue2中的watcher。
测试结果
执行yarn test
PS D:\user\desktop\mini-vue> yarn test
yarn run v1.22.10
$ jest
PASS src/reactivity/tests/effect.spec.ts
PASS src/reactivity/tests/index.spec.ts
PASS src/reactivity/tests/reactive.spec.ts
Test Suites: 3 passed, 3 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.075 s
Ran all test suites.
Done in 2.59s.
可以看到我们之前写的3个测试文件都已经通过。
总结
这节课,我们完成了effect的主要功能,通过effect(fn)返回一个用ReactiveEffect包裹的实例对象,当执行函数的时候会自动调用内部的run方法,实际上也就是通过effect传入的fn。
下一节,我们将一起来实现依赖收集和触发依赖。