ref的主要逻辑
- 在Effect中调用的这个ref变量后对依赖进行收集
- 当这个变量的.value 进行修改后,触发收集到的依赖
在vue3中的使用方法
当变量a.value发生变化时effect中的b会被重新赋值并打印。
实现方法
在调用自己实现的effectWatch时会将当前的执行函数(依赖)使用一个变量记录下来(currentEffect),然后马上执行一次=>fn(),当fn中的a.value被调用时触发的MyRef的depend方法。depend将当前记录的依赖添加到effects中记录。当调用set时执行notice方法,会将effects中的依赖在执行一遍
export class MyRef {
constructor(value){
this._val = value;
this.effects = new Set();
}
get value(){
this.depend()
return this._val;
}
set value(val){
this._val = val;
this.notice();
}
depend(){
if(currentEffect){
this.effects.add(currentEffect);
}
}
notice(){
this.effects.forEach(effect=>{
effect()
})
}
}
let currentEffect = null;
export function effectWatch(fn) {
currentEffect = fn
fn();
currentEffect = null
}
reactive的主要逻辑
- 可以传入一个json对象,自动将每个属性都转换成ref响应式对象。
实现方法
使用map来存储所有reactive,key为传入的json对象(raw),对应的value也是一个map,这个map的key是属性的名字,value的值是MyRef对象。
剩下的逻辑和ref差不多,get的时候收集依赖,set的时候触发依赖,不过要注意初始化的时候要进行判断
let targetsMap = new Map();
export function reactive(raw) {
return new Proxy(raw,{
get(target,key){
let dep = getDep(target,key);
dep.depend();
return Reflect.get(target,key);
},
set(target,key,value){
let dep = getDep(target,key);
const result = Reflect.set(target,key,value);
dep.notice();
return result
}
})
}
function getDep(raw, key) {
let depsMap = targetsMap.get(raw);
if(!depsMap){
depsMap = new Map();
targetsMap.set(raw,depsMap);
}
let dep = depsMap.get(key);
if(!dep){
dep = new MyRef();
depsMap.set(key,dep);
}
return dep;
}