Vue3响应式原理实现(简单手写)

参照源码

//设置缓存
let toProxy = new WeakMap()
let toRaw = new WeakMap()
//proxy配置
const baseHander = {
  get(target, key){
    const res = Reflect.get(target, key)
    // 收集依赖
    track(target, key)
    // 递归寻找
    return typeof res=='object' ? reactive(res) : res
  },
  set(target, key, val){
    const info = {oldValue: target[key], newValue:val}
    const res = Reflect.set(target, key, val)
    // 派发更新
    trigger(target, key, info)
    return res
  }
}
function reactive(target){
  // 查询缓存
  let observed = toProxy.get(target)
  if(observed){
    return observed
  }
  if(toRaw.get(target)){
    return target
  }
  //vue3响应式采用proxy处理
  observed = new Proxy(target, baseHander)
  // 设置缓存
  toProxy.set(target, observed)
  toRaw.set(observed, target)
  return observed
}

let effectStack = []
let tagetMap = new WeakMap()
/*
{
  target:{
    age: []  (set),
    name:[effect]
  }
}
*/
//派发更新
function trigger(target, key, info){
  const depsMap = tagetMap.get(target)
  if(depsMap===undefined){
    return 
  }
  const effects = new Set()
  const computedRunners = new Set()
  if(key){
    let deps = depsMap.get(key)
    deps.forEach(effect=>{
      if(effect.computed){
        computedRunners.add(effect)
      }else{
        effects.add(effect)
      }
    })
  }
  // const run = effect=> effect()
  effects.forEach(effect=> effect())
  computedRunners.forEach(effect=> effect())
}
//依赖收集
function track(target, key){
  let effect = effectStack[effectStack.length-1]
  if(effect){
    let depsMap = tagetMap.get(target)
    if(depsMap===undefined){
      depsMap = new Map()
      tagetMap.set(target, depsMap)
    }
    let dep = depsMap.get(key)
    if(dep===undefined){
      dep = new Set()
      depsMap.set(key, dep)
    }
    if(!dep.has(effect)){
      dep.add(effect)
      effect.deps.push(dep)
    }
  }
}

// 存储effect
function effect(fn,options={}){
  let e = createReactiveEffect(fn, options)
  // 没有考虑compueted
  if(!options.lazy){
    e()
  }
  return e
}

function createReactiveEffect(fn,options){
  const effect = function effect(...args){
    return run( effect, fn , args)
  }
  effect.deps = []
  effect.computed = options.computed
  effect.lazy = options.lazy
  return effect

}
//数据变更内容存入栈中
function run(effect, fn , args){
  if(effectStack.indexOf(effect)===-1){
    try{
      effectStack.push(effect)
      return fn(...args)
    }
    finally{
      effectStack.pop()
    }
  }
}

function computed(fn){
  //lazy设置缓存
  const runner = effect(fn,{computed:true, lazy:true})
  return {
    effect:runner,
    get value(){
      return runner()
    }
  }
}

简单实现-手写

//手写响应式
let currentEffect;
class Dep {
    constructor() {
       this.effects = new Set()//依赖收集集合,使用set防止其重复收集 
    }
    //依赖收集
    depend() {
        if(currentEffect){
            this.effects.add(currentEffect)
        }
    }
    //派发更新
    notice() {
        //遍历依次去执行收集到的依赖
        this.effects.forEach(effect=>{
            effect()
        })
    }
}

//建立键与dep直接的一一对应关系
let 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
}

//响应式
function reactivity(obj) {
    return new Proxy(obj,{
        get(target,key){
            const dep = getDep(target,key)
            //收集依赖
            dep.depend()
            return Reflect.get(target,key)
        },
        set(target,key,newVal){
            const dep = getDep(target,key)
            const ret = Reflect.set(target,key,newVal)
            //设置值之后再去触发更新
            dep.notice()
            return ret
        }
    })
}

//监听变化
function effectWatch(effect) {
   currentEffect = effect
   effect()//第一次先执行依次
   currentEffect = null
}



let obj = reactivity({
    count:1
})
let b
effectWatch(()=>{
    b = obj.count + 1
    console.log(b)
})

obj.count = 2
obj.count = 3
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值