目标
实现响应式数据,类似下面这样,存在两个方法:reactive、watchEffect,reactive用于定义响应式数据,watchEffect用于监听数据变化。
const { reactive, watchEffect } = require('./reactivity')
const obj = reactive({
a: 10,
})
let b
watchEffect(() => {
b = obj.a + 10
console.log('b更新了', b)
})
obj.a = 20
思路
要监听数据变化,需要利用Object.defineProperty或者Proxy,这里选用Proxy使用代理的方式,在get时添加依赖,在set时触发依赖,来对数据进行监听。
实现步骤
依赖管理
定义Dep类来对依赖进行管理。在get时调用depend方法收集依赖,set时调用notice触发依赖。
let currentEffect
class Dep {
constructor() {
this.effects = new Set()
}
// 收集依赖
depend() {
if (currentEffect) {
this.effects.add(currentEffect)
}
}
// 触发依赖
notice() {
this.effects.forEach((effect) => effect())
}
}
watchEffect
该方法是一个高阶函数,参数为一个函数,将该参数暂存在currentEffect中,调用effect时将收集到依赖,依赖收集完成后,将currentEffect重置。
function watchEffect(effect) {
currentEffect = effect
effect()
currentEffect = null
}
reactive
reactive方法返回一个代理target对象的proxy,在proxy中代理get和set实现对数据的监听。
function reactive(target) {
return new Proxy(target, {
get(target, key) {
// 收集依赖
const dep = getDep(target, key)
dep.depend()
return Reflect.get(target, key)
},
set(target, key, value) {
const dep = getDep(target, key)
Reflect.set(target, key, value)
// 触发依赖
dep.notice()
},
})
}
const targetMap = new Map()
function getDep(target, key) {
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (!dep) {
dep = new Dep()
depsMap.set(key, dep)
}
return dep
}