const state = reactive({name: 'name'})
delete state.name // 调用 deleteProperty
'name' in state // 调用 has
for(let key in state){} // 调用ownkeys
state.name = 'jdlyp' // 调用set
多次触发更新处理
对proto和对象都进行代理的时候会触发多次更新,源码中对这种现象做了处理
处理方法
// 在set的时候
// don't trigger if target is something up in the prototype chain of original
if (target === toRaw(receiver)) { // 减少原型链的触发
if (!hadKey) { // 添加
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) { // 如果前后置有变化触发修改逻辑
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
// 示例1 这种情况本来会触发两次 处理完只触发一次
let obj = {};
let proto = {a:1}
let proxyProto = new Proxy(proto, {
get(target,key,receiver) {
return Reflect.get(target,key,receiver)
},
set(target,key,value,receiver){
// console.log(proxyProto , receiver == myProxy); // 这个地方要屏蔽的
return Reflect.set(target,key,value,receiver)// 不要考虑原型链的set
}
})
Object.setPrototypeOf(obj,proxyProto); // 给obj赋值会触发proxyProto的set
let myProxy = new Proxy(obj,{ // proxy(obj)
get(target,key,receiver) {
return Reflect.get(target,key,receiver)
},
set(target,key,value,receiver){
console.log(receiver === myProxy)
return Reflect.set(target,key,value,receiver); // 调用reflect.set 会触发原型链的set
}
})
myProxy.a = 100; // 内部的特点
console.log(myProxy.a,proto)
// 多次触发更新
// 示例2 这种情况也只触发一次
let people = reactive({eat:'吃',drink:'喝'}); // 防止
let person = reactive({eat:'吃'});
Object.setPrototypeOf(person,people)
effect(()=>{ //people收集一次 perso都会收集一次
console.log(person.eat,'触发几次'); // 这里访问的是person.eat 无论处不处理都只触发一次
})
// person上没有找到了父类people 不处理的话会触发两次
person.eat = '呵呵';
数组
1) 收集索引
修改长度要触发索引的触发 改的是length
const arr = reactive([1]);
effect(()=>{
// 通过索引访问可以收集依赖
console.log(arr[0]); // 这里没有收集length
arr.push(1) //这里收集了length
})
// arr[0] = 2; 正常更新值的情况
arr.length = 0; //修改长度要触发索引的触发 改的是length
arr[100] = 2 // 触发length更新
arr.push(1) // 触发length更新
处理方法
depsMap.forEach((dep, key) => { // 如果修改的是长度,要让大于长度的依赖放入
if (key === 'length' || key >= (newValue as number)) {
deps.push(dep)
}
})
2) 长度收集
修改索引 触发长度更新;数组新增属性触发length更新
const arr = reactive([1]);
effect(()=>{
// 通过索引访问可以收集依赖
console.log(arr.length);
})
debugger
arr[100] = 2; // 修改索引,如果是添加应该触发长度更新
3) 数组方法 访问变异方法会访问数组的长度,会对长度进行依赖,这里我们停止收集调用方法产生的依赖
const arr = reactive([]);
effect(()=>{
arr.push(1); // 会修改属性 同时 访问length
console.log('重新push')
})
debugger
arr.push(1); // 修改length
effect
runner.effect = _effect
可以通过runner.effect 访问effect 上的方法
1). effect中嵌套effect的runner
// 数组依赖收集的方式
const { reactive, readonly, toRaw, markRaw, effect, ref } = VueReactivity;
const state = {name:'lyp'}
// 1). effect中嵌套effect的runner 不做处理的话会死循环
debugger
let runner = effect(()=>{
state.name = 'super man';
});
debugger
effect(runner);
处理方法
if ((fn as ReactiveEffectRunner).effect) { // 如果此函数是effect的返回的runner,则找到原函数
fn = (fn as ReactiveEffectRunner).effect.fn
}