Skip to content

Commit 22cc4a7

Browse files
authored
fix(reactivity): ensure that shallow and normal proxies are tracked seperately (close #2843) (#2851)
fix #2843
1 parent 68de9f4 commit 22cc4a7

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

packages/reactivity/__tests__/shallowReactive.spec.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { shallowReactive, isReactive, reactive } from '../src/reactive'
1+
import { isReactive, reactive, shallowReactive } from '../src/reactive'
2+
23
import { effect } from '../src/effect'
34

45
describe('shallowReactive', () => {
@@ -13,6 +14,16 @@ describe('shallowReactive', () => {
1314
expect(isReactive(props.n)).toBe(true)
1415
})
1516

17+
// #2843
18+
test('should allow shallow und normal reactive for same target', async () => {
19+
const original = { foo: {} }
20+
const shallowProxy = shallowReactive(original)
21+
const reactiveProxy = reactive(original)
22+
expect(shallowProxy).not.toBe(reactiveProxy)
23+
expect(isReactive(shallowProxy.foo)).toBe(false)
24+
expect(isReactive(reactiveProxy.foo)).toBe(true)
25+
})
26+
1627
describe('collections', () => {
1728
test('should be reactive', () => {
1829
const shallowSet = shallowReactive(new Set())

packages/reactivity/__tests__/shallowReadonly.spec.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isReactive, isReadonly, shallowReadonly } from '../src'
1+
import { isReactive, isReadonly, readonly, shallowReadonly } from '../src'
22

33
describe('reactivity/shallowReadonly', () => {
44
test('should not make non-reactive properties reactive', () => {
@@ -27,6 +27,16 @@ describe('reactivity/shallowReadonly', () => {
2727
).not.toHaveBeenWarned()
2828
})
2929

30+
// #2843
31+
test('should differentiate from normal readonly calls', async () => {
32+
const original = { foo: {} }
33+
const shallowProxy = shallowReadonly(original)
34+
const reactiveProxy = readonly(original)
35+
expect(shallowProxy).not.toBe(reactiveProxy)
36+
expect(isReadonly(shallowProxy.foo)).toBe(false)
37+
expect(isReadonly(reactiveProxy.foo)).toBe(true)
38+
})
39+
3040
describe('collection/Map', () => {
3141
;[Map, WeakMap].forEach(Collection => {
3242
test('should make the map/weak-map readonly', () => {

packages/reactivity/src/baseHandlers.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {
55
ReactiveFlags,
66
Target,
77
readonlyMap,
8-
reactiveMap
8+
reactiveMap,
9+
shallowReactiveMap,
10+
shallowReadonlyMap
911
} from './reactive'
1012
import { TrackOpTypes, TriggerOpTypes } from './operations'
1113
import {
@@ -80,7 +82,15 @@ function createGetter(isReadonly = false, shallow = false) {
8082
return isReadonly
8183
} else if (
8284
key === ReactiveFlags.RAW &&
83-
receiver === (isReadonly ? readonlyMap : reactiveMap).get(target)
85+
receiver ===
86+
(isReadonly
87+
? shallow
88+
? shallowReadonlyMap
89+
: readonlyMap
90+
: shallow
91+
? shallowReactiveMap
92+
: reactiveMap
93+
).get(target)
8494
) {
8595
return target
8696
}

packages/reactivity/src/reactive.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ export interface Target {
2828
}
2929

3030
export const reactiveMap = new WeakMap<Target, any>()
31+
export const shallowReactiveMap = new WeakMap<Target, any>()
3132
export const readonlyMap = new WeakMap<Target, any>()
33+
export const shallowReadonlyMap = new WeakMap<Target, any>()
3234

3335
const enum TargetType {
3436
INVALID = 0,
@@ -92,7 +94,8 @@ export function reactive(target: object) {
9294
target,
9395
false,
9496
mutableHandlers,
95-
mutableCollectionHandlers
97+
mutableCollectionHandlers,
98+
reactiveMap
9699
)
97100
}
98101

@@ -106,7 +109,8 @@ export function shallowReactive<T extends object>(target: T): T {
106109
target,
107110
false,
108111
shallowReactiveHandlers,
109-
shallowCollectionHandlers
112+
shallowCollectionHandlers,
113+
shallowReactiveMap
110114
)
111115
}
112116

@@ -143,7 +147,8 @@ export function readonly<T extends object>(
143147
target,
144148
true,
145149
readonlyHandlers,
146-
readonlyCollectionHandlers
150+
readonlyCollectionHandlers,
151+
readonlyMap
147152
)
148153
}
149154

@@ -160,15 +165,17 @@ export function shallowReadonly<T extends object>(
160165
target,
161166
true,
162167
shallowReadonlyHandlers,
163-
shallowReadonlyCollectionHandlers
168+
shallowReadonlyCollectionHandlers,
169+
shallowReadonlyMap
164170
)
165171
}
166172

167173
function createReactiveObject(
168174
target: Target,
169175
isReadonly: boolean,
170176
baseHandlers: ProxyHandler<any>,
171-
collectionHandlers: ProxyHandler<any>
177+
collectionHandlers: ProxyHandler<any>,
178+
proxyMap: WeakMap<Target, any>
172179
) {
173180
if (!isObject(target)) {
174181
if (__DEV__) {
@@ -185,7 +192,6 @@ function createReactiveObject(
185192
return target
186193
}
187194
// target already has corresponding Proxy
188-
const proxyMap = isReadonly ? readonlyMap : reactiveMap
189195
const existingProxy = proxyMap.get(target)
190196
if (existingProxy) {
191197
return existingProxy

0 commit comments

Comments
 (0)