简单的reactive
最近在项目中使用vue3 看到了一个讲解reactive的视频 顺便记录一下
需要了解前置知识
直接开始吧
创建 targetMap activeEffect effect
const targetMap = new WeakMap()// targetMap 存储每个对象在更新时应重新运行的效果
let activeEffect = null
function effect(eff) {
activeEffect = eff;
activeEffect();
activeEffect = null;
}
创建一个track函数追踪对象
// 接收一个对象 及对象的key
function track(target,key) {
if(activeEffect){
let depsMap = targetMap.get(target)// weakMap 的键值必须是对象, 拿到对象的
if(!depsMap){// 如果这个对象没有被监听
targetMap.set(target,(depsMap= new Map()))// targetMap添加当前对象为key value 为一个 map
}
let dep = depsMap.get(key)//获取监听到的key
if(!dep) { // key 未被监听追踪
// 将追踪的key 设置为一个 new Set
depsMap.set(key,(deps= new Set()))
}
dep.add(activeEffect)// 添加一个依赖函数
}
}
在创建一个trigger函数 触发
// 接收一个 target(触发的对象) 触发的key 对象属性
function trigger(target,key){
const depsMap = targetMap.get(target)
if(!depsMap) {// 此对象是否被追踪
return;
}
let dep = depsMap.get(key)
if(dep){// 执行依赖的函数
dep.forEach(effect => effect())
}
}
创建一个reactive 函数
需要用到 Proxy
function reactive(target) {
const handler = {
get(target,key,receiver){
let result = Reflect.get(target,key,receiver)
// 调用 track
track(target,key)
return result
},
set(target,key,value,receiver){
let oldValue = target[key]
let result = Reflect.set(target,key,value,receiver)
if(result && oldValue !== value){// 当改变对象的key
// 调用 trigger
trigger(target,key)
}
return result
}
}
return new Proxy(target,handler)
}
测试一下
let product = reactive({
price:2,
quantity:5
})
let total = 0
effect(()=>{
total = product.price * product.quantity
})
console.log(total) // 10
product.price = 3
console.log(total) // 15
衍生一下 ref computed
ref 可以包装任意的类型 ref的使用 需要.value 需要用到对象的get set
function ref(raw){
let r = {
get value(){
track(r, "value");
return raw
},
set value(val) {
if(val !== raw)
raw = val
trigger(r, "value");
}
}
return r
}
function computed(fn) {
let result = ref();
effect(() => {
result.value = fn();
});
return result;
}