美文网首页
vue3源码之reactive

vue3源码之reactive

作者: 晗笑书生 | 来源:发表于2020-03-15 22:08 被阅读0次

    vue3源码之reactive.ts解析

    reactivity是vue响应式的核心 这块在vue3中完全重构了 采用proxy的方式 完全摒弃了defineProperty的api

    1. 定义了4个WeakMap来存储和记录跟踪对应关系
      2个 WeakSet 来存储只读的值和非响应式的值
      rawToReactive, reactiveToRaw,
      rawToReadonly,readonlyToRaw
      这4个用来记录raw-reactive raw-readonly的对一个关系
      readonlyValues 标记只读值存入到这里
      nonReactiveValues 标记非响应式的值存入到这里

    2 collectionTypes用来记录集合的类型 用于区分不样的handler处理 集合对象使用collectionHandlers来处理 ([Set, Map, WeakMap, WeakSet])
    基本的对象 makeup()'Object,Array,Map,Set,WeakMap,WeakSet'

    3 canObserve 是否需要响应式 排除不是vue组件 不是VNode 不是非响应式的值 且是可以观察的对象 !value._isVue &&
    !value._isVNode &&
    isObservableType(toRawType(value)) &&
    !nonReactiveValues.has(value)

    4 Reactive 函数都是调用 createReactiveObject
    核心代码如下

    // createReactiveObject
     const handlers = collectionTypes.has(target.constructor)
        ? collectionHandlers
        : baseHandlers
      observed = new Proxy(target, handlers)
      toProxy.set(target, observed)
      toRaw.set(observed, target)
      return observed
    
    import { isObject, toRawType } from '@vue/shared'
    import {
      mutableHandlers,
      readonlyHandlers,
      shallowReadonlyHandlers,
      shallowReactiveHandlers
    } from './baseHandlers'
    import {
      mutableCollectionHandlers,
      readonlyCollectionHandlers
    } from './collectionHandlers'
    import { UnwrapRef, Ref, isRef } from './ref'
    import { makeMap } from '@vue/shared'
    
    // WeakMaps that store {raw <-> observed} pairs.
    const rawToReactive = new WeakMap<any, any>()
    const reactiveToRaw = new WeakMap<any, any>()
    const rawToReadonly = new WeakMap<any, any>()
    const readonlyToRaw = new WeakMap<any, any>()
    
    // WeakSets for values that are marked readonly or non-reactive during
    // observable creation.
    const readonlyValues = new WeakSet<any>()
    const nonReactiveValues = new WeakSet<any>()
    
    const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
    const isObservableType = /*#__PURE__*/ makeMap(
      'Object,Array,Map,Set,WeakMap,WeakSet'
    )
    
    const canObserve = (value: any): boolean => {
      return (
        !value._isVue &&
        !value._isVNode &&
        isObservableType(toRawType(value)) &&
        !nonReactiveValues.has(value)
      )
    }
    
    // only unwrap nested ref
    type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
    
    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 (readonlyToRaw.has(target)) {
        return target
      }
      // target is explicitly marked as readonly by user
      if (readonlyValues.has(target)) {
        return readonly(target)
      }
      if (isRef(target)) {
        return target
      }
      return createReactiveObject(
        target,
        rawToReactive,
        reactiveToRaw,
        mutableHandlers,
        mutableCollectionHandlers
      )
    }
    
    export function readonly<T extends object>(
      target: T
    ): Readonly<UnwrapNestedRefs<T>> {
      // value is a mutable observable, retrieve its original and return
      // a readonly version.
      if (reactiveToRaw.has(target)) {
        target = reactiveToRaw.get(target)
      }
      return createReactiveObject(
        target,
        rawToReadonly,
        readonlyToRaw,
        readonlyHandlers,
        readonlyCollectionHandlers
      )
    }
    
    // Return a reactive-copy of the original object, where only the root level
    // properties are readonly, and does NOT unwrap refs nor recursively convert
    // returned properties.
    // This is used for creating the props proxy object for stateful components.
    export function shallowReadonly<T extends object>(
      target: T
    ): Readonly<{ [K in keyof T]: UnwrapNestedRefs<T[K]> }> {
      return createReactiveObject(
        target,
        rawToReadonly,
        readonlyToRaw,
        shallowReadonlyHandlers,
        readonlyCollectionHandlers
      )
    }
    
    // Return a reactive-copy of the original object, where only the root level
    // properties are reactive, and does NOT unwrap refs nor recursively convert
    // returned properties.
    export function shallowReactive<T extends object>(target: T): T {
      return createReactiveObject(
        target,
        rawToReactive,
        reactiveToRaw,
        shallowReactiveHandlers,
        mutableCollectionHandlers
      )
    }
    
    function createReactiveObject(
      target: unknown,
      toProxy: WeakMap<any, any>,
      toRaw: WeakMap<any, any>,
      baseHandlers: ProxyHandler<any>,
      collectionHandlers: ProxyHandler<any>
    ) {
      if (!isObject(target)) {
        if (__DEV__) {
          console.warn(`value cannot be made reactive: ${String(target)}`)
        }
        return target
      }
      // target already has corresponding Proxy
      let observed = toProxy.get(target)
      if (observed !== void 0) {
        return observed
      }
      // target is already a Proxy
      if (toRaw.has(target)) {
        return target
      }
      // only a whitelist of value types can be observed.
      if (!canObserve(target)) {
        return target
      }
      const handlers = collectionTypes.has(target.constructor)
        ? collectionHandlers
        : baseHandlers
      observed = new Proxy(target, handlers)
      toProxy.set(target, observed)
      toRaw.set(observed, target)
      return observed
    }
    
    export function isReactive(value: unknown): boolean {
      return reactiveToRaw.has(value) || readonlyToRaw.has(value)
    }
    
    export function isReadonly(value: unknown): boolean {
      return readonlyToRaw.has(value)
    }
    
    export function toRaw<T>(observed: T): T {
      return reactiveToRaw.get(observed) || readonlyToRaw.get(observed) || observed
    }
    
    export function markReadonly<T>(value: T): T {
      readonlyValues.add(value)
      return value
    }
    
    export function markNonReactive<T>(value: T): T {
      nonReactiveValues.add(value)
      return value
    }
    

    相关文章

      网友评论

          本文标题:vue3源码之reactive

          本文链接:https://www.haomeiwen.com/subject/xwkiehtx.html