From f413ef924e5b83568dd69708698caafeb8539de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E6=9E=9C=E5=B1=B1=E5=A4=A7=E5=9C=A3?= Date: Thu, 14 Nov 2024 15:23:14 +0000 Subject: [PATCH 1/2] fix(reactivity): check rawValue exists in target via set.add vuejs#8647 --- .../reactivity/__tests__/reactive.spec.ts | 22 +++++++++++++++++++ packages/reactivity/src/collectionHandlers.ts | 16 +++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts index aabd954568a..f6abd42fd10 100644 --- a/packages/reactivity/__tests__/reactive.spec.ts +++ b/packages/reactivity/__tests__/reactive.spec.ts @@ -112,6 +112,28 @@ describe('reactivity/reactive', () => { expect(dummy).toBe(false) }) + // #8647 + test('observing nest reactive in set', () => { + const observed = reactive({}) + const observedSet = reactive(new Set([observed])) + expect(observedSet.size).toBe(1) + if (observedSet.has(observed)) { + // expect nothing happens + observedSet.add(observed) + } + expect(observedSet.size).toBe(1) + + const observedMap = reactive(new Map()) + observedMap.set('key', observed) + expect(observedMap.size).toBe(1) + + if (observedMap.has(observed)) { + // expect nothing happens + observedMap.set('key1', observed) + } + expect(observedMap.size).toBe(1) + }) + test('observed value should proxy mutations to original (Object)', () => { const original: any = { foo: 1 } const observed = reactive(original) diff --git a/packages/reactivity/src/collectionHandlers.ts b/packages/reactivity/src/collectionHandlers.ts index 048b7f38863..e5533cdc74b 100644 --- a/packages/reactivity/src/collectionHandlers.ts +++ b/packages/reactivity/src/collectionHandlers.ts @@ -167,15 +167,19 @@ function createInstrumentations( } : { add(this: SetTypes, value: unknown) { - if (!shallow && !isShallow(value) && !isReadonly(value)) { - value = toRaw(value) - } const target = toRaw(this) const proto = getProto(target) - const hadKey = proto.has.call(target, value) + // 先获取原始值 + const rawValue = + !shallow && !isShallow(value) && !isReadonly(value) + ? toRaw(value) + : value + const hadKey = + proto.has.call(target, rawValue) || + (value !== rawValue && proto.has.call(target, value)) if (!hadKey) { - target.add(value) - trigger(target, TriggerOpTypes.ADD, value, value) + target.add(rawValue) + trigger(target, TriggerOpTypes.ADD, rawValue, rawValue) } return this }, From e26787a92f8a1121f0e56c48793979b951e76022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E6=9E=9C=E5=B1=B1=E5=A4=A7=E5=9C=A3?= Date: Fri, 15 Nov 2024 10:22:36 +0000 Subject: [PATCH 2/2] chore: just for set --- packages/reactivity/__tests__/reactive.spec.ts | 10 ---------- packages/reactivity/src/collectionHandlers.ts | 11 +++++------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts index f6abd42fd10..47673ddd9e9 100644 --- a/packages/reactivity/__tests__/reactive.spec.ts +++ b/packages/reactivity/__tests__/reactive.spec.ts @@ -122,16 +122,6 @@ describe('reactivity/reactive', () => { observedSet.add(observed) } expect(observedSet.size).toBe(1) - - const observedMap = reactive(new Map()) - observedMap.set('key', observed) - expect(observedMap.size).toBe(1) - - if (observedMap.has(observed)) { - // expect nothing happens - observedMap.set('key1', observed) - } - expect(observedMap.size).toBe(1) }) test('observed value should proxy mutations to original (Object)', () => { diff --git a/packages/reactivity/src/collectionHandlers.ts b/packages/reactivity/src/collectionHandlers.ts index e5533cdc74b..e110b976832 100644 --- a/packages/reactivity/src/collectionHandlers.ts +++ b/packages/reactivity/src/collectionHandlers.ts @@ -169,17 +169,16 @@ function createInstrumentations( add(this: SetTypes, value: unknown) { const target = toRaw(this) const proto = getProto(target) - // 先获取原始值 - const rawValue = + const valueToAdd = !shallow && !isShallow(value) && !isReadonly(value) ? toRaw(value) : value const hadKey = - proto.has.call(target, rawValue) || - (value !== rawValue && proto.has.call(target, value)) + proto.has.call(target, valueToAdd) || + (value !== valueToAdd && proto.has.call(target, value)) if (!hadKey) { - target.add(rawValue) - trigger(target, TriggerOpTypes.ADD, rawValue, rawValue) + target.add(valueToAdd) + trigger(target, TriggerOpTypes.ADD, valueToAdd, valueToAdd) } return this },