Skip to content

Commit d943612

Browse files
authored
fix(reactivity): avoid duplicate raw/proxy entries in Set.add (#14545)
1 parent 16ef165 commit d943612

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

packages/reactivity/__tests__/collections/Set.spec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { effect, isReactive, reactive, toRaw } from '../../src'
1+
import {
2+
effect,
3+
isReactive,
4+
reactive,
5+
readonly,
6+
shallowReactive,
7+
toRaw,
8+
} from '../../src'
29

310
describe('reactivity/collections', () => {
411
function coverCollectionFn(collection: Set<any>, fnName: string) {
@@ -403,6 +410,34 @@ describe('reactivity/collections', () => {
403410
expect(dummy).toBe(false)
404411
})
405412

413+
it('should not add readonly versions of existing raw values', () => {
414+
const rawValue = {}
415+
const wrappedValue = readonly(rawValue)
416+
const set = reactive(new Set([rawValue]))
417+
418+
expect(set.has(wrappedValue)).toBe(true)
419+
420+
set.add(wrappedValue)
421+
422+
expect(set.size).toBe(1)
423+
expect(toRaw(set).has(rawValue)).toBe(true)
424+
expect(toRaw(set).has(wrappedValue)).toBe(false)
425+
})
426+
427+
it('should not add proxy versions of existing raw values to shallow sets', () => {
428+
const rawValue = {}
429+
const wrappedValue = reactive(rawValue)
430+
const set = shallowReactive(new Set([rawValue]))
431+
432+
expect(set.has(wrappedValue)).toBe(true)
433+
434+
set.add(wrappedValue)
435+
436+
expect(set.size).toBe(1)
437+
expect(toRaw(set).has(rawValue)).toBe(true)
438+
expect(toRaw(set).has(wrappedValue)).toBe(false)
439+
})
440+
406441
it('should warn when set contains both raw and reactive versions of the same object', () => {
407442
const raw = new Set()
408443
const rawKey = {}

packages/reactivity/src/collectionHandlers.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,17 @@ function createInstrumentations(
169169
add(this: SetTypes, value: unknown) {
170170
const target = toRaw(this)
171171
const proto = getProto(target)
172+
const rawValue = toRaw(value)
172173
const valueToAdd =
173174
!shallow && !isShallow(value) && !isReadonly(value)
174-
? toRaw(value)
175+
? rawValue
175176
: value
176177
const hadKey =
177178
proto.has.call(target, valueToAdd) ||
178-
(value !== valueToAdd && proto.has.call(target, value))
179+
(hasChanged(value, valueToAdd) &&
180+
proto.has.call(target, value)) ||
181+
(hasChanged(rawValue, valueToAdd) &&
182+
proto.has.call(target, rawValue))
179183
if (!hadKey) {
180184
target.add(valueToAdd)
181185
trigger(target, TriggerOpTypes.ADD, valueToAdd, valueToAdd)

0 commit comments

Comments
 (0)