const obj = {text: 'hello world'}
function effect() {
document.body.innerText = obj.text
}
每次当obj.text的值变化的时,希望函数effet会重新执行:
obj.text = 'hello vue3'
effect()
响应式基本思路
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角色关系:
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)