|
|
@@ -1,4 +1,4 @@
|
|
|
-import { isObject, toRawType } from '@vue/shared'
|
|
|
+import { isObject, toRawType, def } from '@vue/shared'
|
|
|
import {
|
|
|
mutableHandlers,
|
|
|
readonlyHandlers,
|
|
|
@@ -13,25 +13,38 @@ import { UnwrapRef, Ref } 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>()
|
|
|
+// 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 rawValues = new WeakSet<any>()
|
|
|
+export const enum ReactiveFlags {
|
|
|
+ skip = '__v_skip',
|
|
|
+ isReactive = '__v_isReactive',
|
|
|
+ isReadonly = '__v_isReadonly',
|
|
|
+ raw = '__v_raw',
|
|
|
+ reactive = '__v_reactive',
|
|
|
+ readonly = '__v_readonly'
|
|
|
+}
|
|
|
+
|
|
|
+interface Target {
|
|
|
+ __v_skip?: boolean
|
|
|
+ __v_isReactive?: boolean
|
|
|
+ __v_isReadonly?: boolean
|
|
|
+ __v_raw?: any
|
|
|
+ __v_reactive?: any
|
|
|
+ __v_readonly?: 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 => {
|
|
|
+const canObserve = (value: Target): boolean => {
|
|
|
return (
|
|
|
- !value._isVNode &&
|
|
|
+ !value.__v_skip &&
|
|
|
isObservableType(toRawType(value)) &&
|
|
|
- !rawValues.has(value) &&
|
|
|
!Object.isFrozen(value)
|
|
|
)
|
|
|
}
|
|
|
@@ -42,13 +55,12 @@ 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)) {
|
|
|
+ if (target && (target as Target).__v_isReadonly) {
|
|
|
return target
|
|
|
}
|
|
|
return createReactiveObject(
|
|
|
target,
|
|
|
- rawToReactive,
|
|
|
- reactiveToRaw,
|
|
|
+ false,
|
|
|
mutableHandlers,
|
|
|
mutableCollectionHandlers
|
|
|
)
|
|
|
@@ -60,8 +72,7 @@ export function reactive(target: object) {
|
|
|
export function shallowReactive<T extends object>(target: T): T {
|
|
|
return createReactiveObject(
|
|
|
target,
|
|
|
- rawToReactive,
|
|
|
- reactiveToRaw,
|
|
|
+ false,
|
|
|
shallowReactiveHandlers,
|
|
|
mutableCollectionHandlers
|
|
|
)
|
|
|
@@ -72,8 +83,7 @@ export function readonly<T extends object>(
|
|
|
): Readonly<UnwrapNestedRefs<T>> {
|
|
|
return createReactiveObject(
|
|
|
target,
|
|
|
- rawToReadonly,
|
|
|
- readonlyToRaw,
|
|
|
+ true,
|
|
|
readonlyHandlers,
|
|
|
readonlyCollectionHandlers
|
|
|
)
|
|
|
@@ -88,17 +98,15 @@ export function shallowReadonly<T extends object>(
|
|
|
): Readonly<{ [K in keyof T]: UnwrapNestedRefs<T[K]> }> {
|
|
|
return createReactiveObject(
|
|
|
target,
|
|
|
- rawToReadonly,
|
|
|
- readonlyToRaw,
|
|
|
+ true,
|
|
|
shallowReadonlyHandlers,
|
|
|
readonlyCollectionHandlers
|
|
|
)
|
|
|
}
|
|
|
|
|
|
function createReactiveObject(
|
|
|
- target: unknown,
|
|
|
- toProxy: WeakMap<any, any>,
|
|
|
- toRaw: WeakMap<any, any>,
|
|
|
+ target: Target,
|
|
|
+ isReadonly: boolean,
|
|
|
baseHandlers: ProxyHandler<any>,
|
|
|
collectionHandlers: ProxyHandler<any>
|
|
|
) {
|
|
|
@@ -108,15 +116,16 @@ function createReactiveObject(
|
|
|
}
|
|
|
return target
|
|
|
}
|
|
|
+ // target is already a Proxy, return it.
|
|
|
+ // excpetion: calling readonly() on a reactive object
|
|
|
+ if (target.__v_raw && !(isReadonly && target.__v_isReactive)) {
|
|
|
+ return target
|
|
|
+ }
|
|
|
// target already has corresponding Proxy
|
|
|
- let observed = toProxy.get(target)
|
|
|
+ let observed = isReadonly ? target.__v_readonly : target.__v_reactive
|
|
|
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
|
|
|
@@ -125,30 +134,34 @@ function createReactiveObject(
|
|
|
? collectionHandlers
|
|
|
: baseHandlers
|
|
|
observed = new Proxy(target, handlers)
|
|
|
- toProxy.set(target, observed)
|
|
|
- toRaw.set(observed, target)
|
|
|
+ def(
|
|
|
+ target,
|
|
|
+ isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive,
|
|
|
+ observed
|
|
|
+ )
|
|
|
return observed
|
|
|
}
|
|
|
|
|
|
export function isReactive(value: unknown): boolean {
|
|
|
- value = readonlyToRaw.get(value) || value
|
|
|
- return reactiveToRaw.has(value)
|
|
|
+ if (isReadonly(value)) {
|
|
|
+ return isReactive((value as Target).__v_raw)
|
|
|
+ }
|
|
|
+ return !!(value && (value as Target).__v_isReactive)
|
|
|
}
|
|
|
|
|
|
export function isReadonly(value: unknown): boolean {
|
|
|
- return readonlyToRaw.has(value)
|
|
|
+ return !!(value && (value as Target).__v_isReadonly)
|
|
|
}
|
|
|
|
|
|
export function isProxy(value: unknown): boolean {
|
|
|
- return readonlyToRaw.has(value) || reactiveToRaw.has(value)
|
|
|
+ return isReactive(value) || isReadonly(value)
|
|
|
}
|
|
|
|
|
|
export function toRaw<T>(observed: T): T {
|
|
|
- observed = readonlyToRaw.get(observed) || observed
|
|
|
- return reactiveToRaw.get(observed) || observed
|
|
|
+ return (observed && toRaw((observed as Target).__v_raw)) || observed
|
|
|
}
|
|
|
|
|
|
export function markRaw<T extends object>(value: T): T {
|
|
|
- rawValues.add(value)
|
|
|
+ def(value, ReactiveFlags.skip, true)
|
|
|
return value
|
|
|
}
|