3、带你一步步实现vue3源码之effect

178 阅读2分钟

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

下一节,我们将一起来实现依赖收集和触发依赖。