vue3源码学习笔记- reactivity

135 阅读3分钟

简介

响应式模块主要是将对象经过Proxy代理,同时根据shallow,readonly不同的参数,组合成四种响应式类型。由于经过代理的过程基本一样,只是handler处理方式存在差异。故采用柯里化的思想,基于createReactiveObject生成四种类型响应式方法。

主要方法分析

createReactiveObject

  • 参数说明
    • target: 要被代理的对象
    • isReadonly: 是否只读
    • baseHandlers: 具体处理方法对象
    • collectionHandlers: 集合类型处理方法对象
    • proxyMap: 全局代理存储对应,避免重复代理
  • 处理逻辑
    • 只对Object处理,非对象直接返回原对象
    • 已经是响应式了,直接返回
    • 查找proxyMap是否已经存在,若是则表示代理过,直接取已经代理过的对象
    • 对象中也要再判断一次类型,只有是Object,Array,Map/WeakMap,Set/WeakSet这几种数据类型才做代理
    • 调用Proxy返回代理对象,同时将代理过之后的对象存入缓存中

    集合类型则调集合对应的handler

全局定义变量

  1. 响应式类型
    • skip
    • reactive
    • readonly
    • shallow
  2. 4种对应的WeakMap,存储经过Proxy代理之后的对象,避免重复代理

WeakMap对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
正由于这样的弱引用,WeakMap 的 key 是不可枚举的(没有方法能给出所有的 key)。如果key 是可枚举的话,其列表将会受垃圾回收机制的影响,从而得到不确定的结果。因此,如果你想要这种类型对象的 key 值的列表,你应该使用 Map。

  1. 判断Reactive对象属于那种具体类型
  • isReadonly 根据ReactiveFlags.IS_READONLY变量判断
  • isReactive 如果是isReadonly,就判断RAW类型是否Reactive
  • isShallow 根据ReactiveFlags.IS_SHALLOW变量判断
  • isProxy 是Reactive或者Readonly
  1. toRaw
    先判断target是否存在ReactiveFlags.RAW,存在则对raw对象继续进行toRaw调用,否则返回本身
  2. markRaw
    标记Raw类型,即设置对应对象的ReactiveFlags.SKIP设置为true
  3. toReactive
    是对象则调用reactive方法,否则返回自身
  4. toReadonly

handler

baseHandlers

通过createGetter,createSetter两个方法传入不同的参数(isReadonly和shallow)组合成对应的handler

createGetter

不同的key处理策略不一样

  • 先处理当访问的key是ReactiveFlags的情况,直接返回target
    • 访问RAW属性时,先判断当前receiver与对应的Map缓存中取出代理对象是否一致
  • target是数组,且不是只读,访问的keyarrayInstrumentations中时 createArrayInstrumentations
  • 需要遍历数组所有元素的方法['includes', 'indexOf', 'lastIndexOf']
  • 会改变元素length属性的方法['push', 'pop', 'shift', 'unshift', 'splice'] 通过Refelct.get获取原来对象的值之后,处理返回结果res
  • keySymbol时,如果是内建属性或者访问的是不收集依赖的属性(__proto__,__v_isRef,__isVue)时,直接返回获取的值
  • 非只读时,收集依赖
  • shallow为真时,表示只处理第一层,直接返回
  • 如果是Ref类型,需要unwrap,直接返回值,但是针对数组或者访问的是key是整型,则不做unwrap处理
  • 如果返回的是一个Object,则需要再次调用reactive方法,继续递归处理

    访问时,才收集依赖

createSetter

先获取旧值oldValue,如果旧值是只读的,并且是一个Ref且新值不是Ref,则返回false

  • 要设置的key是否是新增,数组下标,且小于数组长度,或者是在对象已有属性中,则都不是新增
  • trigger触发

收集依赖

track

pauseTracking

resetTracking

trigger