我正在参加「掘金·启航计划」
前言
在上节中,我们实现了 effect 最核心的内容了,本节是对上节内容做一个完善,对 effect 添加返回值,这允许我们在合适的时机手动去执行 effect 的回调,这给了我们开发者更多可操作的空间,会在什么场景下用到返回值呢,比如:需要手动的触发 effect 是否重新执行。
源码分析
在分析案例和自己实现之前,我们先看下源码里面 effect 方法的返回值里面包含什么。
最后返回的 runner 其实就是 _effect 实例的 run 方法,使用 bind 是为了绑定 this 指向 _effect,便于解决后续直接调用 runner,this 指向 window。同时 又将 _effect 实例绑定到 runner 对象的 effect 变量上,便于可以调用到 stop 方法。
案例分析
基于以上的源码分析后,我们大概掌握了它是如何使用的了,我们使用 runner 来手动控制是否执行 effect 回调。
const { effect, reactive } = VueReactivity;
const state = reactive({ name: "lisi", age: 12 });
let runner = effect(() => {
document.body.innerHTML = state.age;
});
runner.effect.stop();
setTimeout(() => {
state.age++;
setTimeout(() => {
runner();
}, 1000);
}, 1000);
源码实现
- 在
ReactiveEffect类里添加stop方法,主要逻辑是调用cleanupEffect清除 当前的effect的deps。 - 在
effect方法里 返回 被bind后的run方法,并将该实例放到effect变量上,便于我们调用它上面的 stop方法。
// packages/reactivity/src/effect.ts
+ export interface ReactiveEffectRunner<T = any> {
+ (): T
+ effect: ReactiveEffect
+ }
class ReactiveEffect<T = any> {
+ stop() {
+ if (this.active) {
+ this.active = false
+ cleanupEffect(this)
+ }
+ }
}
export function effect<T = any>(fn: () => T) {
// 创建 响应式 effect
const _effect = new ReactiveEffect(fn);
_effect.run();
+ const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
+ runner.effect = _effect
+ return runner
}
总结
上面仅仅实现了 effect 有了让我们手动执行的功能,还有比如 effect 的第二个参数 options 配置对象在本节里面没有实现,感兴趣的同学可以自己去看下怎么实现的,我们下节再看下怎么写吧。