diff --git a/packages/reactivity/__tests__/readonly.spec.ts b/packages/reactivity/__tests__/readonly.spec.ts index b9edb440fb7..f2c19d9d4bf 100644 --- a/packages/reactivity/__tests__/readonly.spec.ts +++ b/packages/reactivity/__tests__/readonly.spec.ts @@ -1,14 +1,14 @@ import { - reactive, - readonly, - toRaw, + effect, + isProxy, isReactive, isReadonly, markRaw, - effect, + reactive, + readonly, ref, shallowReadonly, - isProxy + toRaw } from '../src' /** @@ -461,5 +461,13 @@ describe('reactivity/readonly', () => { `Set operation on key "foo" failed: target is readonly.` ).not.toHaveBeenWarned() }) + + test('should allow shallow und normal reactive for same target', () => { + const target = { foo: 1 } + const shallowProxy = shallowReadonly(target) + const normalProxy = readonly(target) + + expect(normalProxy).not.toBe(shallowProxy) + }) }) }) diff --git a/packages/reactivity/__tests__/shallowReactive.spec.ts b/packages/reactivity/__tests__/shallowReactive.spec.ts index 5997d045b5a..ebd8a42998b 100644 --- a/packages/reactivity/__tests__/shallowReactive.spec.ts +++ b/packages/reactivity/__tests__/shallowReactive.spec.ts @@ -1,4 +1,5 @@ -import { shallowReactive, isReactive, reactive } from '../src/reactive' +import { isReactive, reactive, shallowReactive } from '../src/reactive' + import { effect } from '../src/effect' describe('shallowReactive', () => { @@ -13,6 +14,14 @@ describe('shallowReactive', () => { expect(isReactive(props.n)).toBe(true) }) + test('should allow shallow und normal reactive for same target', () => { + const target = { foo: 1 } + const shallowProxy = shallowReactive(target) + const normalProxy = reactive(target) + + expect(normalProxy).not.toBe(shallowProxy) + }) + describe('collections', () => { test('should be reactive', () => { const shallowSet = shallowReactive(new Set()) diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts index 5f57a3c9f90..335e5d6513c 100644 --- a/packages/reactivity/src/baseHandlers.ts +++ b/packages/reactivity/src/baseHandlers.ts @@ -1,29 +1,32 @@ import { - reactive, - readonly, - toRaw, + ITERATE_KEY, + pauseTracking, + resetTracking, + track, + trigger +} from './effect' +import { ReactiveFlags, Target, + reactive, + reactiveMap, + readonly, readonlyMap, - reactiveMap + shallowReactiveMap, + shallowReadonlyMap, + toRaw } from './reactive' import { TrackOpTypes, TriggerOpTypes } from './operations' import { - track, - trigger, - ITERATE_KEY, - pauseTracking, - resetTracking -} from './effect' -import { - isObject, - hasOwn, - isSymbol, + extend, hasChanged, + hasOwn, isArray, isIntegerKey, - extend + isObject, + isSymbol } from '@vue/shared' + import { isRef } from './ref' const builtInSymbols = new Set( @@ -77,7 +80,15 @@ function createGetter(isReadonly = false, shallow = false) { return isReadonly } else if ( key === ReactiveFlags.RAW && - receiver === (isReadonly ? readonlyMap : reactiveMap).get(target) + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap + ).get(target) ) { return target } diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index cea41a191ae..5be8e259dda 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -1,16 +1,16 @@ -import { isObject, toRawType, def } from '@vue/shared' +import { Ref, UnwrapRef } from './ref' +import { def, isObject, toRawType } from '@vue/shared' +import { + mutableCollectionHandlers, + readonlyCollectionHandlers, + shallowCollectionHandlers +} from './collectionHandlers' import { mutableHandlers, readonlyHandlers, shallowReactiveHandlers, shallowReadonlyHandlers } from './baseHandlers' -import { - mutableCollectionHandlers, - readonlyCollectionHandlers, - shallowCollectionHandlers -} from './collectionHandlers' -import { UnwrapRef, Ref } from './ref' export const enum ReactiveFlags { SKIP = '__v_skip', @@ -27,7 +27,9 @@ export interface Target { } export const reactiveMap = new WeakMap() +export const shallowReactiveMap = new WeakMap() export const readonlyMap = new WeakMap() +export const shallowReadonlyMap = new WeakMap() const enum TargetType { INVALID = 0, @@ -91,7 +93,8 @@ export function reactive(target: object) { target, false, mutableHandlers, - mutableCollectionHandlers + mutableCollectionHandlers, + reactiveMap ) } @@ -105,7 +108,8 @@ export function shallowReactive(target: T): T { target, false, shallowReactiveHandlers, - shallowCollectionHandlers + shallowCollectionHandlers, + shallowReactiveMap ) } @@ -142,7 +146,8 @@ export function readonly( target, true, readonlyHandlers, - readonlyCollectionHandlers + readonlyCollectionHandlers, + readonlyMap ) } @@ -159,7 +164,8 @@ export function shallowReadonly( target, true, shallowReadonlyHandlers, - readonlyCollectionHandlers + readonlyCollectionHandlers, + shallowReadonlyMap ) } @@ -167,7 +173,8 @@ function createReactiveObject( target: Target, isReadonly: boolean, baseHandlers: ProxyHandler, - collectionHandlers: ProxyHandler + collectionHandlers: ProxyHandler, + proxyMap: WeakMap ) { if (!isObject(target)) { if (__DEV__) { @@ -184,7 +191,6 @@ function createReactiveObject( return target } // target already has corresponding Proxy - const proxyMap = isReadonly ? readonlyMap : reactiveMap const existingProxy = proxyMap.get(target) if (existingProxy) { return existingProxy