]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): Map/Set identity methods should work even if raw value contains...
authorEvan You <yyx990803@gmail.com>
Fri, 6 Mar 2020 16:10:02 +0000 (11:10 -0500)
committerEvan You <yyx990803@gmail.com>
Fri, 6 Mar 2020 16:10:02 +0000 (11:10 -0500)
fix #799

packages/reactivity/__tests__/collections/Map.spec.ts
packages/reactivity/__tests__/collections/Set.spec.ts
packages/reactivity/__tests__/reactiveArray.spec.ts
packages/reactivity/src/baseHandlers.ts
packages/reactivity/src/collectionHandlers.ts

index 1b5ae573192521a4de18d92cf30e2e172dbd1739..c4e5476baf5ff54829649a476b7ecb5cdb8849c6 100644 (file)
@@ -348,5 +348,19 @@ describe('reactivity/collections', () => {
       map.set('foo', NaN)
       expect(mapSpy).toHaveBeenCalledTimes(1)
     })
+
+    it('should work with reactive keys in raw map', () => {
+      const raw = new Map()
+      const key = reactive({})
+      raw.set(key, 1)
+      const map = reactive(raw)
+
+      expect(map.has(key)).toBe(true)
+      expect(map.get(key)).toBe(1)
+
+      expect(map.delete(key)).toBe(true)
+      expect(map.has(key)).toBe(false)
+      expect(map.get(key)).toBeUndefined()
+    })
   })
 })
index 9e3efa166f1fe47fa96f0e90b2ac6e01f4e82f28..f0a627ee0d524941ea8d9e6fd9f3aa7b46eca727 100644 (file)
@@ -368,5 +368,17 @@ describe('reactivity/collections', () => {
       })
       expect(dummy).toBe(2)
     })
+
+    it('should work with reactive entries in raw set', () => {
+      const raw = new Set()
+      const entry = reactive({})
+      raw.add(entry)
+      const set = reactive(raw)
+
+      expect(set.has(entry)).toBe(true)
+
+      expect(set.delete(entry)).toBe(true)
+      expect(set.has(entry)).toBe(false)
+    })
   })
 })
index b61116e28b13c1dcfebe152a7043eaa0041b7dbf..d91d447822653e84acb50aadcc3ef13c95172810 100644 (file)
@@ -67,6 +67,14 @@ describe('reactivity/reactive/Array', () => {
     expect(arr.lastIndexOf(observed, 1)).toBe(-1)
   })
 
+  test('Array identity methods should work if raw value contains reactive objects', () => {
+    const raw = []
+    const obj = reactive({})
+    raw.push(obj)
+    const arr = reactive(raw)
+    expect(arr.includes(obj)).toBe(true)
+  })
+
   test('Array identity methods should be reactive', () => {
     const obj = {}
     const arr = reactive([obj, {}])
index 0aaeade83e465b2258fe1106caecc619e6d7aa4b..932f4ebec0d6de10beeab83f63e468b0febd38df 100644 (file)
@@ -23,7 +23,14 @@ const arrayInstrumentations: Record<string, Function> = {}
     for (let i = 0, l = (this as any).length; i < l; i++) {
       track(arr, TrackOpTypes.GET, i + '')
     }
-    return arr[key](...args.map(toRaw))
+    // we run the method using the orignal args first (which may be reactive)
+    const res = arr[key](...args)
+    if (res === -1 || res === false) {
+      // if that didn't work, run it again using raw values.
+      return arr[key](...args.map(toRaw))
+    } else {
+      return res
+    }
   }
 })
 
index 095537cc4fd871a6099ea2022cdcc8600502397a..e173ce302d94ca31b69cc910ca15367f0bd74d07 100644 (file)
@@ -26,16 +26,22 @@ function get(
   wrap: typeof toReactive | typeof toReadonly
 ) {
   target = toRaw(target)
-  key = toRaw(key)
-  track(target, TrackOpTypes.GET, key)
-  return wrap(getProto(target).get.call(target, key))
+  const rawKey = toRaw(key)
+  track(target, TrackOpTypes.GET, rawKey)
+  const { has, get } = getProto(target)
+  if (has.call(target, key)) {
+    return wrap(get.call(target, key))
+  } else if (has.call(target, rawKey)) {
+    return wrap(get.call(target, rawKey))
+  }
 }
 
 function has(this: CollectionTypes, key: unknown): boolean {
   const target = toRaw(this)
-  key = toRaw(key)
-  track(target, TrackOpTypes.HAS, key)
-  return getProto(target).has.call(target, key)
+  const rawKey = toRaw(key)
+  track(target, TrackOpTypes.HAS, rawKey)
+  const has = getProto(target).has
+  return has.call(target, key) || has.call(target, rawKey)
 }
 
 function size(target: IterableCollections) {
@@ -73,13 +79,16 @@ function set(this: MapTypes, key: unknown, value: unknown) {
 }
 
 function deleteEntry(this: CollectionTypes, key: unknown) {
-  key = toRaw(key)
   const target = toRaw(this)
-  const proto = getProto(target)
-  const hadKey = proto.has.call(target, key)
-  const oldValue = proto.get ? proto.get.call(target, key) : undefined
+  const { has, get, delete: del } = getProto(target)
+  let hadKey = has.call(target, key)
+  if (!hadKey) {
+    key = toRaw(key)
+    hadKey = has.call(target, key)
+  }
+  const oldValue = get ? get.call(target, key) : undefined
   // forward the operation before queueing reactions
-  const result = proto.delete.call(target, key)
+  const result = del.call(target, key)
   if (hadKey) {
     trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
   }
@@ -177,7 +186,7 @@ const mutableInstrumentations: Record<string, Function> = {
     return get(this, key, toReactive)
   },
   get size() {
-    return size(this as unknown as IterableCollections)
+    return size((this as unknown) as IterableCollections)
   },
   has,
   add,