vue3.0源码核心--reactivity核心模块reactive

reactivity核心模块reactive


前言

上文我们学习了vue.3.1响应式系统reactivity,今天我们来系统学习下核心模块reactive源码
Vue3中响应数据核心是 reactive , reactive 中的实现是由 proxy 加 effect 组合,先来看一下 reactive 方法的定义

一、reactive


export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
  // if trying to observe a readonly proxy, return the readonly version.
  // 如果目标对象是一个只读的响应数据,则直接返回目标对象
  if (target && (target as Target).__v_isReadonly) {
    return target
  }

  // 否则调用  createReactiveObject 创建 observe
  return createReactiveObject(
    target, 
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}

二、createReactiveObject

createReactiveObject的作用是将target转化为响应式对象,话不多说上代码
代码版本3.1.4


function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>
  proxyMap: WeakMap<Target, any>
) {
  // 被转化的target必须是object
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`)
    }
    return target
  }
  // target is already a Proxy, return it.
  // exception: calling readonly() on a reactive object
    if (
    target[ReactiveFlags.RAW] &&
    !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
  ) {
    return target
  }

  // target already has corresponding Proxy 目标已经有相应的代理
  const existingProxy = proxyMap.get(target)
  if (existingProxy) {
    return existingProxy
  }
  // only a whitelist of value types can be observed.白名单
  //只有target在可转化类型白名单里才会进行转化,否则直接返回target
  const targetType = getTargetType(target)
  if (targetType === TargetType.INVALID) {
    return target
  }
  // 转化proxy对象,并将转化后的对象挂载到target的__v_readonly(只读模式)或__v_reactive(非只读模式)属性上
  const proxy = new Proxy(
    target,
  // Set、WeakSet、Map、WeakMap类型用的collectionHandlers,其他对象类型使用baseHandlers
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  proxyMap.set(target, proxy)
  return proxy
}

那么在这里3.1是优化了3.0的createReactiveObject方法内可转化类型白名单方法的实现,会校验target的__v_skip是否为true、target类型是否在白名单里、target是否为冻结对象,同时满足才会继续转化

三、目标对象

代码如下(版本3.1.4):

// 同时满足3个条即为可以观察的目标对象
// 1. 没有打上__v_skip标记
// 2. 是可以观察的值类型
// 3. 没有被frozen
function getTargetType(value: Target) {
  return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
    ? TargetType.INVALID
    : targetTypeMap(toRawType(value))
}

// 可以被观察的值类型
function targetTypeMap(rawType: string) {
  switch (rawType) {
    case 'Object':
    case 'Array':
      return TargetType.COMMON
    case 'Map':
    case 'Set':
    case 'WeakMap':
    case 'WeakSet':
      return TargetType.COLLECTION
    default:
      return TargetType.INVALID
  }
}
const enum TargetType {
  INVALID = 0,
  COMMON = 1,
  COLLECTION = 2
}

这里对于3.0有一些改变,3.0是直接判断是否是可以观察的值类型,并没有区分COMMON类型与COLLECTION类型。

总结

reactive 是做为整个响应式的入口,负责处理目标对象是否可观察以及是否已被观察的逻辑,最后使用 Proxy 进行目标对象的代理,Proxy 重点的逻辑处理在 Handlers ,下面我们会介绍collectionHandlers与baseHandlers,并逐步对于前置知识进行补充

上一篇:vue3.0-reactivityApi


下一篇:Vue3 -- ref & reactive & toRefs & toRef响应式引用