Skip to content

reactive API

  • reactive 函数拥有单个参数 target 必须是对象或者数据类型
  • 内部通过了 createReactiveObject 函数执行 把 target 变成一个响应式对象
ts
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 (isReadonly(target)) {
    return target
  }
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}

createReactiveObject

  • createReactiveObject 拥有 5个参数
    • target 表示待变成响应式对象的 对象或者数组
    • isReadonly 是否创建只读对象
    • baseHandles 表示普通对象和数组类型数据的响应式对象处理器
    • collectionHandles 表示集合类型数据的响应式处理器
    • proxyMap 表示原始对象和响应式对象的缓存映射图
  • createReactiveObject 主要做
    • 判断 target 是不是对象或者数组 不是直接返回
    • 如果已经是响应式对象 再次执行 reactive 直接返回该响应式对象 ■ 内部通过 target.__v_raw 属性判断 target 是否已经是响应式对象
    • 如果同一个原始数据多次执行 reactive 返回相同的响应式对象
    • 对 原始对象的类型进一步进行限制 会通过 getTargetType 函数判断 比如 Date 类型 RegExp 类型 promise 类型 都是不可变成响应式对象 直接返回
  • 通过 proxy 劫持 target 对象 变成响应式 把 new Proxy 创建的 proxy 实例称做响应式对象
    • 如果是集合类型数据 使用 collectionHandles
    • 如果是非集合类型数据 使用 baseHandles
  • 把原始对象 target 作为 key 响应式对象 proxy 作为 value 存储到 map 类型的对象 proxyMap
    • 这就是为什么多次执行 reactive 函数返回同一个对象
ts

function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  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 specific value types can be observed.
  const targetType = getTargetType(target)
  if (targetType === TargetType.INVALID) {
    return target
  }
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  proxyMap.set(target, proxy)
  return proxy
}

mutableHandlers

  • 劫持了对 proxy 对象对一些操作
  • 访问对象属性会触发 get 函数
  • 设置对象属性会触发 set 函数
  • 删除对象属性会触发 deleteProperty 函数
  • in 操作符会触发 has 函数
  • Object.getOwnPropertyNames 访问对象属性触发 ownKeys 函数
ts
export const mutableHandlers: ProxyHandler<object> = {
  get,
  set,
  deleteProperty,
  has,
  ownKeys
}

Welcome to the site