Vue3响应式个人理解(一)响应式基本原理

文章参考了霍春阳的《Vue.js设计与实现》,是自己在阅读过程中的一些思考和理解

伪代码

const bocket = new Set()
const data = {
  name: 'mean'
}
const proxy = new Proxy(data, {
  //重写get函数,当读取这个值时,在处理函数桶中加入修改函数
  get(target, key) {
    bucket.add(effect)
    return target[key]
  },
  //重写set函数,当修改这个值时,执行桶中所有函数
  set(target, key, newValue) { 
    target[key] = newValue
    bocket.forEach(fn => fn())
    return true
  }
})
//读取数据放在页面
function effect() {
  document.body.innerText = proxy.name
}
effect()
//3秒后修改值
setTimeout(() => {
  proxy.name = 'newName'
}, 3000)

通过副作用函数,读取代理值。当数据发生改变时,在set函数中再次调用副作用函数,再重新读一遍修改后的值,放在原本的位置,达到响应式的功能。

完善一点的响应式

  //全局变量
  let activeEffect
  //静态数据
  const data = {
    name: 'mean'
  }
  //存储所有数据的函数,用到了WeakMap的特性
  //这里的映射为bocket--->WeakMap<target, Map()>
  const bocket = new WeakMap()

  const proxy = new Proxy(data, {
    get(target, proxy) {
      if(!activeEffect) return
      //从桶中获取当前对象的Map,因为bocket中可以存储对个对象
      let depsMap = bocket.get(target)
      //如果没有则立即创建一个,并放在bocket中
      //这里映射为 target--->Map<key,Set()>
      if(!depsMap) {
        bocket.set(target, (depsMap = new Map()))
      }
      //从对象的众多key中拿到我们要修改的key的Set()集合
      //如果没有则立即创建,并加入到depsMap中
      //这里的映射为key--->Set(fn,fn,fn....)
      let deps = depsMap.get(proxy)
      if(!deps) {
        depsMap.set(proxy, (deps = new Set()))
      }
      //将我们传入的修改函数加入到对应key的Set()集合中
      deps.add(activeEffect)
      //返回读取的值
      return target[proxy]
    },
    set(target, proxy, value, reciver) {
      //原对象中修改要变的值
      target[proxy] = value
      //获取到target的Map,没有则返回
      const depsMap = bocket.get(target)
      if(!depsMap) return
      //拿到要修改的key的Set集合()
      const effects = depsMap.get(proxy)
      //依次执行集合中的函数
      effects && effects.forEach(fn => fn())
      return true
    }
  })

  //暴露的effect函数,透给用户使用,用于对数据进行修改和调用
  function effect(fn) {
    activeEffect = fn
    activeEffect()
  }

  effect(() => {
    document.body.innerText = proxy.name
  })
  //2秒后修改数据
  setTimeout(() => {
    proxy.name = 'fiht'
  }, 2000);

最后可以把get和set中间的操作部分分割出来,方便管理

function track(target, proxy) {
      if(!activeEffect) return
      
      let depsMap = bocket.get(target)
      if(!depsMap) {
        bocket.set(target, (depsMap = new Map()))
      }

      let deps = depsMap.get(proxy)
      if(!deps) {
        depsMap.set(proxy, (deps = new Set()))
      }

      deps.add(activeEffect)
  }

  function trigger(target, proxy) {
    const depsMap = bocket.get(target)
      if(!depsMap) return
   
      const effects = depsMap.get(proxy)

      effects && effects.forEach(fn => fn())
  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值