vue3 响应式(一)

59 阅读1分钟
const obj = {text: 'hello world'}
function effect() {
    document.body.innerText = obj.text
}

每次当obj.text的值变化的时,希望函数effet会重新执行:

obj.text = 'hello vue3'
effect()

响应式基本思路

image.png

const obj = new Proxy(data, {
  get(target, key) {
    // 依赖收集,将函数存储到‘桶’中
    track(target, key)

    return target[key]
  },
  set(target, key, newVal) {
    target[key] = newVal
    // 取出函数并执行
    trigger(target, key)
  }
})

track & trigger

const bucket = new WeakMap()

function track(target, key) {
    if (!activeEffect) return
    let depsMap = bucket.get(target)

    if (!depsMap) {
      bucket.set(target, (depsMap = new Map()))
    }

    let deps = depsMap.get(key)

    if (!deps) {
      depsMap.set(key, (deps = new Set()))
    }

    deps.add(activeEffect)
}

function trigger(target, key) {
    const depsMap = bucket.get(target)
    if (!depsMap) return

    const effects = depsMap.get(key)

    effects && effects.forEach(fn => fn())
}

用WeakMap存储数据,是因为WeakMap是弱引用,不影响垃圾回收;一旦执行完毕,就会将对象从内存中移除。

target、key、effect角色关系:

image.png

effect

// 存储调用的事件
let activeEffect
function effect (fn) {
    activeEffect = fn
    fn()
}

demo

const data = { text: 'hello world' }

effect(() => { 
  console.log('effect run')
  document.body.innerHTML = obj.text 
})

setTimeout(() => {
    obj.text = 'hello vue3'
}, 1000)