]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): shallowReactive map "unwraps" the nested refs (#8503)
authorLiuSeen <91084928+liuseen-l@users.noreply.github.com>
Tue, 16 Jul 2024 07:07:06 +0000 (15:07 +0800)
committerGitHub <noreply@github.com>
Tue, 16 Jul 2024 07:07:06 +0000 (15:07 +0800)
fix #8501
fix #11249

packages/reactivity/__tests__/reactive.spec.ts
packages/reactivity/__tests__/shallowReactive.spec.ts
packages/reactivity/src/collectionHandlers.ts

index bd4ec402bb2a1e0e9fd9c3768df31ead88d032da..1c25c49121bf4e59b82f691a5a1a173fc5e0b66c 100644 (file)
@@ -2,6 +2,8 @@ import { isRef, ref } from '../src/ref'
 import {
   isProxy,
   isReactive,
+  isReadonly,
+  isShallow,
   markRaw,
   reactive,
   readonly,
@@ -359,4 +361,25 @@ describe('reactivity/reactive', () => {
     const c = computed(() => {})
     expect(isProxy(c)).toBe(false)
   })
+
+  test('The results of the shallow and readonly assignments are the same (Map)', () => {
+    const map = reactive(new Map())
+    map.set('foo', shallowReactive({ a: 2 }))
+    expect(isShallow(map.get('foo'))).toBe(true)
+
+    map.set('bar', readonly({ b: 2 }))
+    expect(isReadonly(map.get('bar'))).toBe(true)
+  })
+
+  test('The results of the shallow and readonly assignments are the same (Set)', () => {
+    const set = reactive(new Set())
+    set.add(shallowReactive({ a: 2 }))
+    set.add(readonly({ b: 2 }))
+    let count = 0
+    for (const i of set) {
+      if (count === 0) expect(isShallow(i)).toBe(true)
+      else expect(isReadonly(i)).toBe(true)
+      count++
+    }
+  })
 })
index e9b64d39b36aef655d16734dbb2f662e7fad0840..cb5ef8e6d977eeac43954ad0b7dd6a7c266b794b 100644 (file)
@@ -123,6 +123,29 @@ describe('shallowReactive', () => {
       shallowSet.forEach(x => expect(isReactive(x)).toBe(false))
     })
 
+    test('Setting a reactive object on a shallowReactive map', () => {
+      const msg = ref('ads')
+      const bar = reactive({ msg })
+      const foo = shallowReactive(new Map([['foo1', bar]]))
+      foo.set('foo2', bar)
+
+      expect(isReactive(foo.get('foo2'))).toBe(true)
+      expect(isReactive(foo.get('foo1'))).toBe(true)
+    })
+
+    test('Setting a reactive object on a shallowReactive set', () => {
+      const msg = ref(1)
+      const bar = reactive({ msg })
+      const foo = reactive({ msg })
+
+      const deps = shallowReactive(new Set([bar]))
+      deps.add(foo)
+
+      deps.forEach(dep => {
+        expect(isReactive(dep)).toBe(true)
+      })
+    })
+
     // #1210
     test('onTrack on called on objectSpread', () => {
       const onTrackFn = vi.fn()
index 7c4b36fbe943d83defa7f1eaf085abffc10e2ea0..c39e3ed48cdfb832a40e669222a0dee98808c47e 100644 (file)
@@ -1,4 +1,10 @@
-import { toRaw, toReactive, toReadonly } from './reactive'
+import {
+  isReadonly,
+  isShallow,
+  toRaw,
+  toReactive,
+  toReadonly,
+} from './reactive'
 import {
   ITERATE_KEY,
   MAP_KEY_ITERATE_KEY,
@@ -72,8 +78,10 @@ function size(target: IterableCollections, isReadonly = false) {
   return Reflect.get(target, 'size', target)
 }
 
-function add(this: SetTypes, value: unknown) {
-  value = toRaw(value)
+function add(this: SetTypes, value: unknown, _isShallow = false) {
+  if (!_isShallow && !isShallow(value) && !isReadonly(value)) {
+    value = toRaw(value)
+  }
   const target = toRaw(this)
   const proto = getProto(target)
   const hadKey = proto.has.call(target, value)
@@ -84,8 +92,10 @@ function add(this: SetTypes, value: unknown) {
   return this
 }
 
-function set(this: MapTypes, key: unknown, value: unknown) {
-  value = toRaw(value)
+function set(this: MapTypes, key: unknown, value: unknown, _isShallow = false) {
+  if (!_isShallow && !isShallow(value) && !isReadonly(value)) {
+    value = toRaw(value)
+  }
   const target = toRaw(this)
   const { has, get } = getProto(target)
 
@@ -263,8 +273,12 @@ function createInstrumentations() {
       return size(this as unknown as IterableCollections)
     },
     has,
-    add,
-    set,
+    add(this: SetTypes, value: unknown) {
+      return add.call(this, value, true)
+    },
+    set(this: MapTypes, key: unknown, value: unknown) {
+      return set.call(this, key, value, true)
+    },
     delete: deleteEntry,
     clear,
     forEach: createForEach(false, true),