computed
let count = ref(0);
let getCount = computed(()=>{ // 此方法默认不执行
return count.value + 10;
})
// 当访问 getCount.value 的时候会执行会执行effect后面会说明
// getCount.value 执行一次
// getCount.value 还要不要缓存? 还要不要执行?不要了走缓存了
// 更新了 count.value = 100 就会执行了 getCount 从新被执行了但是不会立刻重新计算,为什么不会立即执行因为需要 getCount.value 手动触发一下 this.effect下面会解释
// 当我用 getCount.value的时候才会重新计算。
// computed 一定是一个effect 一定是一个lazy的 有缓存 我们执行的逻辑还不一定是 return count.value + 10; 这个因为改了 count.value没有马上执行 一定用了 scheduler
// getCount.value 多次访问值没有变 需要有个缓存 缓存的标识
创建computed.ts
// vue2 和 vue3 computed的原理是不相同的 计算属性也需要收集依赖。 vue2 计算属性没有收集依赖的能力的
export function computed(getterOrOptions // 可以是getter或者是一个options){
let getter;
let setter;
if(isFunction(getterOrOptions)) {
getter = getterOrOptions;
setter = () => {};
} else {
const df = () => {}
getter = getterOrOptions.getter || df;
setter = getterOrOptions.setter || df;
}
// computed 的返回对象类似ref
return new ComputedRefImpl(getter, setter);
}
class ComputedRefImpl {
private notCache = true; // 默认取值不需要用缓存
private _val = ''; // getCount = computed... getCount.value 的这个_val
public effect = null; // computed默认响应式用就是个effect
constructor(public getter, public setter) {
// 这里的这个effect是从effect.ts里面引入的
this.effect = effect(() => { // 手动调用effect不走scheduler 收集的才走, 有个点需要明确说明一下 this.effect()跑的是 ()=>{} 内部的依赖发生了改变走的是 scheduler
return getter() // 靠着 effect对里面的依赖收集重新执行 getter
},{
lazy: true, // 默认别让他执行起来
scheduler: () => {
// 修改值的时候在把缓存放开
// 如果修改了effect里面的值的时候 getter 值的时候因为有了scheduler所以()=>{}这里面的就不在执行了而执行scheduler
if(!this.notCache){ // 如果getter里面的值发生了改变依赖收集,触发到这里
this.notCache = true; // 注意一下这个时候并没有执行getter要等下面方位了才能执行。所以回答了上面的那个问题如果修改了不能立马响应。
// 为了 --AAA(这个标识下面有一段例子,这里是要在更新的时候手动触发一下ComputedRefImpl这个类本身的属性的更新) 需要做依赖收集 访问的时候就收集它通知更新
trigger(this, TriggerOrTypes.SET, 'value')
}
}
}
}) // 默认创建了一个effect,这个会默认执行但是计算属性不会默认执行,所以需要加一个lazy
}
get value() {
// 比较核心的是在这里
/*
计算属性也需要收集依赖。 vue2 计算属性没有收集依赖的能力的
计算属性本身就是一个effect
computed = effect
里面的依赖属性可以关联上computed
首先需要生成一个effect
创建完了一个类就生成一个effect
public effect = '';
取值的时候 effect 才执行
*/
if(notCache){ // 没有缓存的时候才执行
this._val = this.effect(); // 一取值就执行effect, 这个方法执行完毕后会把用户的执行结果拿回来,不走scheduler这个effect是返回的那个fn.
this.notCache = false; // xx.value xxx.value 第二次就不走 effect了,这样多次取值取的永远是第一次执行后的结果。
}
// 为了 --AAA 需要做依赖收集 访问的时候就收集它
tract(this, TrackOptTypes.Get,'value');
return this._val;
}
set value(val = '') {
this._val = val;
this.setter(this._val);
}
/**
* const myAge = computed({
get(){
}
set(){
}
})
myAage.value = 1; 走到了上面的set里面了 先走 ComputedRefImpl 的 set 再走自定义的set
*/
}
// computed的两种实现方式
computed(() => {})
computed({
set(){},
get(){}
})
const myAge = compute(()=>{
age.value
})
//需要考虑下 --AAA
myAge = effect(()=>{
// 下面那个修改了这里不会更新因为这里没有用age
myAge.value
})这种情况
age.value = 500; // 需要修改 age.value 触发 myAge.value 这个effect的执行