Skip to content

Commit 694cdc0

Browse files
author
Thorsten Luenborg
committed
fix(reactivity): ensure that shallow and normal proxies are tracked seperately
close #2843
1 parent 3626ff0 commit 694cdc0

File tree

4 files changed

+69
-35
lines changed

4 files changed

+69
-35
lines changed

packages/reactivity/__tests__/readonly.spec.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import {
2-
reactive,
3-
readonly,
4-
toRaw,
2+
effect,
3+
isProxy,
54
isReactive,
65
isReadonly,
76
markRaw,
8-
effect,
7+
reactive,
8+
readonly,
99
ref,
1010
shallowReadonly,
11-
isProxy
11+
toRaw
1212
} from '../src'
1313

1414
/**
@@ -461,5 +461,13 @@ describe('reactivity/readonly', () => {
461461
`Set operation on key "foo" failed: target is readonly.`
462462
).not.toHaveBeenWarned()
463463
})
464+
465+
test('should allow shallow und normal reactive for same target', () => {
466+
const target = { foo: 1 }
467+
const shallowProxy = shallowReadonly(target)
468+
const normalProxy = readonly(target)
469+
470+
expect(normalProxy).not.toBe(shallowProxy)
471+
})
464472
})
465473
})

packages/reactivity/__tests__/shallowReactive.spec.ts

+10-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,14 @@ describe('shallowReactive', () => {
1314
expect(isReactive(props.n)).toBe(true)
1415
})
1516

17+
test('should allow shallow und normal reactive for same target', () => {
18+
const target = { foo: 1 }
19+
const shallowProxy = shallowReactive(target)
20+
const normalProxy = reactive(target)
21+
22+
expect(normalProxy).not.toBe(shallowProxy)
23+
})
24+
1625
describe('collections', () => {
1726
test('should be reactive', () => {
1827
const shallowSet = shallowReactive(new Set())

packages/reactivity/src/baseHandlers.ts

+27-16
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
11
import {
2-
reactive,
3-
readonly,
4-
toRaw,
2+
ITERATE_KEY,
3+
pauseTracking,
4+
resetTracking,
5+
track,
6+
trigger
7+
} from './effect'
8+
import {
59
ReactiveFlags,
610
Target,
11+
reactive,
12+
reactiveMap,
13+
readonly,
714
readonlyMap,
8-
reactiveMap
15+
shallowReactiveMap,
16+
shallowReadonlyMap,
17+
toRaw
918
} from './reactive'
1019
import { TrackOpTypes, TriggerOpTypes } from './operations'
1120
import {
12-
track,
13-
trigger,
14-
ITERATE_KEY,
15-
pauseTracking,
16-
resetTracking
17-
} from './effect'
18-
import {
19-
isObject,
20-
hasOwn,
21-
isSymbol,
21+
extend,
2222
hasChanged,
23+
hasOwn,
2324
isArray,
2425
isIntegerKey,
25-
extend
26+
isObject,
27+
isSymbol
2628
} from '@vue/shared'
29+
2730
import { isRef } from './ref'
2831

2932
const builtInSymbols = new Set(
@@ -77,7 +80,15 @@ function createGetter(isReadonly = false, shallow = false) {
7780
return isReadonly
7881
} else if (
7982
key === ReactiveFlags.RAW &&
80-
receiver === (isReadonly ? readonlyMap : reactiveMap).get(target)
83+
receiver ===
84+
(isReadonly
85+
? shallow
86+
? shallowReadonlyMap
87+
: readonlyMap
88+
: shallow
89+
? shallowReactiveMap
90+
: reactiveMap
91+
).get(target)
8192
) {
8293
return target
8394
}

packages/reactivity/src/reactive.ts

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import { isObject, toRawType, def } from '@vue/shared'
1+
import { Ref, UnwrapRef } from './ref'
2+
import { def, isObject, toRawType } from '@vue/shared'
3+
import {
4+
mutableCollectionHandlers,
5+
readonlyCollectionHandlers,
6+
shallowCollectionHandlers
7+
} from './collectionHandlers'
28
import {
39
mutableHandlers,
410
readonlyHandlers,
511
shallowReactiveHandlers,
612
shallowReadonlyHandlers
713
} from './baseHandlers'
8-
import {
9-
mutableCollectionHandlers,
10-
readonlyCollectionHandlers,
11-
shallowCollectionHandlers
12-
} from './collectionHandlers'
13-
import { UnwrapRef, Ref } from './ref'
1414

1515
export const enum ReactiveFlags {
1616
SKIP = '__v_skip',
@@ -27,7 +27,9 @@ export interface Target {
2727
}
2828

2929
export const reactiveMap = new WeakMap<Target, any>()
30+
export const shallowReactiveMap = new WeakMap<Target, any>()
3031
export const readonlyMap = new WeakMap<Target, any>()
32+
export const shallowReadonlyMap = new WeakMap<Target, any>()
3133

3234
const enum TargetType {
3335
INVALID = 0,
@@ -91,7 +93,8 @@ export function reactive(target: object) {
9193
target,
9294
false,
9395
mutableHandlers,
94-
mutableCollectionHandlers
96+
mutableCollectionHandlers,
97+
reactiveMap
9598
)
9699
}
97100

@@ -105,7 +108,8 @@ export function shallowReactive<T extends object>(target: T): T {
105108
target,
106109
false,
107110
shallowReactiveHandlers,
108-
shallowCollectionHandlers
111+
shallowCollectionHandlers,
112+
shallowReactiveMap
109113
)
110114
}
111115

@@ -142,7 +146,8 @@ export function readonly<T extends object>(
142146
target,
143147
true,
144148
readonlyHandlers,
145-
readonlyCollectionHandlers
149+
readonlyCollectionHandlers,
150+
readonlyMap
146151
)
147152
}
148153

@@ -159,15 +164,17 @@ export function shallowReadonly<T extends object>(
159164
target,
160165
true,
161166
shallowReadonlyHandlers,
162-
readonlyCollectionHandlers
167+
readonlyCollectionHandlers,
168+
shallowReadonlyMap
163169
)
164170
}
165171

166172
function createReactiveObject(
167173
target: Target,
168174
isReadonly: boolean,
169175
baseHandlers: ProxyHandler<any>,
170-
collectionHandlers: ProxyHandler<any>
176+
collectionHandlers: ProxyHandler<any>,
177+
proxyMap: WeakMap<Target, any>
171178
) {
172179
if (!isObject(target)) {
173180
if (__DEV__) {
@@ -184,7 +191,6 @@ function createReactiveObject(
184191
return target
185192
}
186193
// target already has corresponding Proxy
187-
const proxyMap = isReadonly ? readonlyMap : reactiveMap
188194
const existingProxy = proxyMap.get(target)
189195
if (existingProxy) {
190196
return existingProxy

0 commit comments

Comments
 (0)