做个有深度的程序员 — YuanGe
实现vue3中的ref、reactive和effect
实现vue3中的ref、reactive和effect

实现vue3中的ref、reactive和effect

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;
}
-->