我们补充一下之前的reactive模块,这里做代理的时候还需要处理对象嵌套对象的情况,要做深度代理
get的时候
- 取了属性之后,如果是对象的话,再次做下代理
- Proxy是取的时候再代理,而不是像vue2一样上来就进行递归,性能提高了很多
computed的使用
也可以这样写
- computed的特点是缓存
- 计算属性中肯定要有一个缓存的标识,如果这个依赖有变化,要重新执行get,没有变化就不重新执行get
- dirty是否是脏的
- 计算属性本质是一个effect,依赖的属性变化了会更新dirty的值,dirty一更新,你再次取值,取的就是最新的,而不是缓存中的
- 计算属性是可以收集effect的
下面我们开始实现
创建computed.ts文件
对参数进行判断
- 判断参数是不是一个函数,如果是一个函数,那么说明只有getter
然后我们写一个类ComputedRefImpl去处理getter和setter
然后我们需要去new一个ReactiveEffect类实例,这个类就是我们之前写过的,用于包装effect的类
- 我们将getter传入ReactiveEffect类里,那么getter里访问到的属性就会被这个effect收集起来,第二个参数就是调度scheduler调度器
然后我们给这个类加上dirty标识,用于缓存
然后我们再加一个value属性,当取值的时候就返回这个value
当取值的时候我们要判断这个值是不是脏的
- 如果是脏的,我们就重新执行effect,然后把执行结果赋值给value
- 取完值后我们就把dirty改成false,多次取值就屏蔽掉
- 依赖的属性变化会触发调度器,当你传了调度器,触发更新的时候就会调用你传入的调度器,不清楚调度器的看之前的文章
但是这样简单更改dirty的值是不会发生重新渲染的,我们要让computed拥有收集依赖的能力
- 再增加一个属性dep,用于收集effect
- 在get的时候进行依赖收集,在调度器里实现更新
- 当我们传入一个Set,这个方法会把当前正在执行的activeEffect放进来
调度器里触发更新
总结:
- 判断参数是一个对象还是一个函数,如果是一个函数说明就只有一个getter
- 增加value属性,当你访问computed的value的时候会触发getter,根据属性dirty来判断是不是脏值,如果是脏值,就进行依赖收集,收集到当前类上的dep属性里,是个Set类型值
- 当你设置值的时候会触发属性的set,里面会触