Vue3响应式原理-computed
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
import { isFunction } from "@vue/shared";
import { activeEffect, ReactiveEffect, trackEffects, triggerEffects } from "./effect";
class ComputedRefImpl {
public effect;
public _value;
public dep;
public _dirty = true;
constructor(getter,public setter) {
this.effect = new ReactiveEffect(getter,()=>{
if(!this._dirty){ // 依赖的值变化更新dirty并触发更新
this._dirty = true;
triggerEffects(this.dep)
}
});
}
get value(){ // 取值的时候进行依赖收集
if(activeEffect){
trackEffects(this.dep || (this.dep = new Set));
}
if(this._dirty){ // 如果是脏值, 执行函数
this._dirty = false;
this._value = this.effect.run();
}
return this._value;
}
set value(newValue){
this.setter(newValue)
}
}
export function computed(getterOrOptions) {
const onlyGetter = isFunction(getterOrOptions); // 传入的是函数就是getter
let getter;
let setter;
if (onlyGetter) {
getter = getterOrOptions;
setter = () => { }
} else {
getter = getterOrOptions.get;
setter = getterOrOptions.set;
}
// 创建计算属性
return new ComputedRefImpl(getter, setter)
创建ReactiveEffect时,传入
scheduler函数,稍后依赖的属性变化时调用此方法!
export function triggerEffects(effects) {
effects = new Set(effects);
for (const effect of effects) {
if (effect !== activeEffect) { // 如果effect不是当前正在运行的effect
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run(); // 重新执行一遍
}
}
}
}
export function trackEffects(dep) { // 收集dep 对应的effect
let shouldTrack = !dep.has(activeEffect)
if (shouldTrack) {
dep.add(activeEffect);
activeEffect.deps.push(dep);
}
}