欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue3 简版reactive实现

程序员文章站 2022-05-17 10:28:57
...

reactive

依赖收集

createReactiveEffect产生effect
触发proxy代理
effect
effect压入effectStack
track依赖收集
effect出栈effectStack

发生属性变化,触发proxy,执行对应的effect

触发trigger
Proxy
执行依赖里面的effect

依赖的结构

type Dep = Set<ReactiveEffect>
type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<any, KeyToDepMap>()

html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>miniReactive</title>
</head>
<body>
    <div id="app"></div>    
</body>
<script src="./index.js"></script>
<script>
    let obj  = reactive({a: 1})
    effect(()=>{
        document.getElementById("app").innerText = obj.a
    })
    setInterval(()=>{
        obj.a ++
    }, 1000)
</script>
</html>

代码实现


function reactive(obj) {
    console.log(typeof obj);
    if (typeof obj !== 'object') {
        return obj
    }
    return new Proxy(obj, {
        // Reflect 的形参和Proxy 的handle基本一样
        get(target, key) {
            let val = Reflect.get(target, key)
            console.log("get:", val);
            track(target, key)
            return val
        },
        set(target, key, value) {
            let res = Reflect.set(target, key, value)
            console.log("set:", value);
            trigger(target, key)
            return res
        },
        deleteProperty(target, key) {
            let res = Reflect.deleteProperty(target, key)
            console.log("deleteproperty:", res);
            trigger(target, key)
            return res
        }
    })
}

let effectStack = []
let targetMap = new WeakMap()

function effect(fn) {
    let effect = createReactiveEffect(fn)
    effect()
    return effect
}

function createReactiveEffect(fn) {
    let effect = function reactiveEffect() {
        try {
            effectStack.push(effect)
            return fn()
        } finally {
            effectStack.pop()
        }
    }
    return effect
}

function track(target, key) {
    let activeEffect = effectStack[effectStack.length - 1]
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    // 注册依赖- 操作集合 key
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, (dep = new Set()))
    }
    if (!dep.has(activeEffect)) {
        dep.add(activeEffect)  
    }
}

function trigger(target, key){
    let depsMap = targetMap.get(target)
    if(!depsMap) return
    
    let deps = depsMap.get(key)
    deps.forEach(dep => {
        dep()
    });
}

相关标签: JavaScript vue