最简化数据依赖收集,参考了vue3

69 阅读1分钟

const targetMap = new Map();
let activeEffeft = null;

function trigger(target, key) {
    const depsMap = targetMap.get(target);
    if (!depsMap) return
    const deps = depsMap.get(key);
    for(let _effet of deps) {
        if (_effet.scheduler) {
            _effet.scheduler();
        } else {
            _effet.run();
        }
    }
}   

function track(target, key) {
    let depsMap = targetMap.get(target);
    if (!depsMap) {
        depsMap = new Map();
        targetMap.set(target, depsMap)
    }
    let deps = depsMap.get(key);
    if (!deps) {
        deps = new Set();
        depsMap.set(key, deps)
    }
    if (activeEffeft) {
        deps.add(activeEffeft)
    }
}

class ReactiveEffect {

    constructor(_fn, scheduler) {
        this._fn = _fn;
        this.scheduler = scheduler;
    }

    run() {
        activeEffeft = this;
        return this._fn();
    }
}

function effect(fn, scheduler) {
    const _effet = new ReactiveEffect(fn, scheduler);
    _effet.run();
}


function reactive(data) {
    
    return new Proxy(data, {
        get(target, key) {
            const res = Reflect.get(target, key);
            track(target, key)
            return res;
        },
        set(target, key, value) {
            const res = Reflect.set(target, key, value);
            trigger(target, key, value)
        }
    })

}

function watch(fn, callback) {
    effect(() => {
        fn()
    }, callback)
}

function computed(getter) {
    return new class {
        _ditry = true;
        effect = null;
        _value = null;
        constructor() {
            this.effect = new ReactiveEffect(getter, () => {
                if (!this._ditry) {
                    this._ditry = true;
                }
            })
        }
        get value() {
            if (this._ditry) {
                this._ditry = false;
                this._value = this.effect.run();
            }
            return this._value;
        }
    }
}


const data = reactive({
    name: 'tom',
    age: 14
})


data.age++;

watch(() => [data.name], () => {
    console.log('name发生变化')
})

const d = computed(() => `${data.name}:${data.age}` )

console.log(d.value);
data.name = 'fsef'
console.log(d.value);
console.log(data.name);