实现vue3的计算属性-详细步骤

218 阅读2分钟

我们补充一下之前的reactive模块,这里做代理的时候还需要处理对象嵌套对象的情况,要做深度代理

get的时候

image.png

  • 取了属性之后,如果是对象的话,再次做下代理
  • Proxy是取的时候再代理,而不是像vue2一样上来就进行递归,性能提高了很多

computed的使用

image.png

也可以这样写

image.png

  • computed的特点是缓存
  • 计算属性中肯定要有一个缓存的标识,如果这个依赖有变化,要重新执行get,没有变化就不重新执行get
  • dirty是否是脏的
  • 计算属性本质是一个effect,依赖的属性变化了会更新dirty的值,dirty一更新,你再次取值,取的就是最新的,而不是缓存中的
  • 计算属性是可以收集effect的

下面我们开始实现

创建computed.ts文件

image.png

对参数进行判断

  • 判断参数是不是一个函数,如果是一个函数,那么说明只有getter

image.png

然后我们写一个类ComputedRefImpl去处理getter和setter

image.png

然后我们需要去new一个ReactiveEffect类实例,这个类就是我们之前写过的,用于包装effect的类

image.png

  • 我们将getter传入ReactiveEffect类里,那么getter里访问到的属性就会被这个effect收集起来,第二个参数就是调度scheduler调度器

然后我们给这个类加上dirty标识,用于缓存

image.png

然后我们再加一个value属性,当取值的时候就返回这个value

image.png

当取值的时候我们要判断这个值是不是脏的

image.png

  • 如果是脏的,我们就重新执行effect,然后把执行结果赋值给value
  • 取完值后我们就把dirty改成false,多次取值就屏蔽掉
  • 依赖的属性变化会触发调度器,当你传了调度器,触发更新的时候就会调用你传入的调度器,不清楚调度器的看之前的文章

但是这样简单更改dirty的值是不会发生重新渲染的,我们要让computed拥有收集依赖的能力

  • 再增加一个属性dep,用于收集effect
  • 在get的时候进行依赖收集,在调度器里实现更新

image.png

  • 当我们传入一个Set,这个方法会把当前正在执行的activeEffect放进来

image.png

调度器里触发更新

image.png

image.png

总结:

  • 判断参数是一个对象还是一个函数,如果是一个函数说明就只有一个getter
  • 增加value属性,当你访问computed的value的时候会触发getter,根据属性dirty来判断是不是脏值,如果是脏值,就进行依赖收集,收集到当前类上的dep属性里,是个Set类型值
  • 当你设置值的时候会触发属性的set,里面会触