Vue3源码实现(三)- 完善 Effect(添加返回值)

111 阅读2分钟

我正在参加「掘金·启航计划」

前言

在上节中,我们实现了 effect 最核心的内容了,本节是对上节内容做一个完善,对 effect 添加返回值,这允许我们在合适的时机手动去执行 effect 的回调,这给了我们开发者更多可操作的空间,会在什么场景下用到返回值呢,比如:需要手动的触发 effect 是否重新执行。

源码分析

在分析案例和自己实现之前,我们先看下源码里面 effect 方法的返回值里面包含什么。

image.png

最后返回的 runner 其实就是 _effect 实例的 run 方法,使用 bind 是为了绑定 this 指向 _effect,便于解决后续直接调用 runnerthis 指向 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);

QQ20221010-122219.gif

源码实现

  • ReactiveEffect 类里添加 stop 方法,主要逻辑是调用 cleanupEffect 清除 当前的 effectdeps
  • 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 配置对象在本节里面没有实现,感兴趣的同学可以自己去看下怎么实现的,我们下节再看下怎么写吧。