介绍
开头继续感谢崔大的mini-vue 项目。
强烈建议大家把项目 down 下来,运行一下,看VUE3 的整体运行逻辑。
实现 computed
computed 这个跟 ref 差不多,都是通过.value的形式调用。
computed 特有的功能就是有缓存。
首先我们创建一个 computed 的文件并导出computed 这个函数。
我们要实现的逻辑都在ComputedRefImpl这个类里面实现。
export function computed(getter) {
return new ComputedRefImpl(getter)
}
以下就是一个简单的 getter的逻辑,获取值的时候,直接返回 getter。
class ComputedRefImpl {
private _getter:any
constructor(getter) {
this._getter = getter
}
get value() {
return this._getter
}
}
接下来比较重要的 computed 的特性,缓存我们用一个变量 dirty 来判断。
这个时候,我们第一次调用 get value 的时候,就用 _value 这个变量把值给缓存起来,第二次调用的时候,直接返回_value
class ComputedRefImpl {
private _getter:any
private _dirty:boolean = true
private _value:any
constructor(getter) {
this._getter = getter
}
get value() {
if(this._dirty) {
this._dirty = false
this.value =this._getter()
}
return this._value
}
}
接下来我们要实现的最关键的一步。
也就是当依赖的响应式数据改变的时候,我们重新去触发一下 computed 的属性。
也就是我们需要引入 effect
this._effect = new ReactiveEffect(getter)
把ReactiveEffect 从 reactive 里面导出来。
当this._dirty 是 true 的 时候,我们就去执行 effect 的 run 方法,也就是把用户想要执行的函数放进去执行。
最后一步也就是利用 schedule 的这个方法,当this._dirty 是 false 的时候,把它改成 true
class ComputedRefImpl {
private _dirty: boolean = true;
private _value: any;
private _effect: any;
constructor(getter) {
this._effect = new ReactiveEffect(getter, () => {
if (!this._dirty) {
this._dirty = true
}
})
}
get value() {
if (this._dirty) {
this._dirty = false
this._value = this._effect.run()
}
return this._value
}
}
结尾
项目已经放到我的 GitHub 上面了,欢迎大家去start。
本次 commit地址:github.com/moyuhaokan/…
我的项目地址:github.com/moyuhaokan/…
再次推荐崔大的项目:github.com/cuixiaorui/…