]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(reactivity): refactor iteration key trigger logic + use more robust Map...
authorEvan You <yyx990803@gmail.com>
Mon, 14 Sep 2020 15:26:34 +0000 (11:26 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 14 Sep 2020 15:26:34 +0000 (11:26 -0400)
packages/reactivity/src/collectionHandlers.ts
packages/reactivity/src/effect.ts
packages/runtime-core/src/apiWatch.ts
packages/shared/src/index.ts
packages/shared/src/toDisplayString.ts

index 24ae1515610187e9e8b9f4b2c500c61224a90d72..6ff76c671b3def7259d030e808016adb00304f28 100644 (file)
@@ -6,7 +6,8 @@ import {
   capitalize,
   hasOwn,
   hasChanged,
-  toRawType
+  toRawType,
+  isMap
 } from '@vue/shared'
 
 export type CollectionTypes = IterableCollections | WeakCollections
@@ -129,7 +130,7 @@ function clear(this: IterableCollections) {
   const target = toRaw(this)
   const hadItems = target.size !== 0
   const oldTarget = __DEV__
-    ? target instanceof Map
+    ? isMap(target)
       ? new Map(target)
       : new Set(target)
     : undefined
@@ -185,9 +186,10 @@ function createIterableMethod(
   ): Iterable & Iterator {
     const target = (this as any)[ReactiveFlags.RAW]
     const rawTarget = toRaw(target)
-    const isMap = rawTarget instanceof Map
-    const isPair = method === 'entries' || (method === Symbol.iterator && isMap)
-    const isKeyOnly = method === 'keys' && isMap
+    const targetIsMap = isMap(rawTarget)
+    const isPair =
+      method === 'entries' || (method === Symbol.iterator && targetIsMap)
+    const isKeyOnly = method === 'keys' && targetIsMap
     const innerIterator = target[method](...args)
     const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive
     !isReadonly &&
index a4d087beadef2d86586f50b65aeb09773580e8d0..495d6714939cdc81f8ccd2766bf2d37b97f71a1d 100644 (file)
@@ -1,5 +1,5 @@
 import { TrackOpTypes, TriggerOpTypes } from './operations'
-import { EMPTY_OBJ, isArray, isIntegerKey } from '@vue/shared'
+import { EMPTY_OBJ, isArray, isIntegerKey, isMap } from '@vue/shared'
 
 // The main WeakMap that stores {target -> key -> dep} connections.
 // Conceptually, it's easier to think of a dependency as a Dep class
@@ -197,19 +197,33 @@ export function trigger(
     if (key !== void 0) {
       add(depsMap.get(key))
     }
+
     // also run for iteration key on ADD | DELETE | Map.SET
-    const shouldTriggerIteration =
-      (type === TriggerOpTypes.ADD &&
-        (!isArray(target) || isIntegerKey(key))) ||
-      (type === TriggerOpTypes.DELETE && !isArray(target))
-    if (
-      shouldTriggerIteration ||
-      (type === TriggerOpTypes.SET && target instanceof Map)
-    ) {
-      add(depsMap.get(isArray(target) ? 'length' : ITERATE_KEY))
-    }
-    if (shouldTriggerIteration && target instanceof Map) {
-      add(depsMap.get(MAP_KEY_ITERATE_KEY))
+    switch (type) {
+      case TriggerOpTypes.ADD:
+        if (!isArray(target)) {
+          add(depsMap.get(ITERATE_KEY))
+          if (isMap(target)) {
+            add(depsMap.get(MAP_KEY_ITERATE_KEY))
+          }
+        } else if (isIntegerKey(key)) {
+          // new index added to array -> length changes
+          add(depsMap.get('length'))
+        }
+        break
+      case TriggerOpTypes.DELETE:
+        if (!isArray(target)) {
+          add(depsMap.get(ITERATE_KEY))
+          if (isMap(target)) {
+            add(depsMap.get(MAP_KEY_ITERATE_KEY))
+          }
+        }
+        break
+      case TriggerOpTypes.SET:
+        if (isMap(target)) {
+          add(depsMap.get(ITERATE_KEY))
+        }
+        break
     }
   }
 
index 9c131067feb76f09fcf2ce1e613e650c3031b510..ac1b1d16d7f694f2d40bb4baf4a33d9aac76d451 100644 (file)
@@ -16,7 +16,9 @@ import {
   isString,
   hasChanged,
   NOOP,
-  remove
+  remove,
+  isMap,
+  isSet
 } from '@vue/shared'
 import {
   currentInstance,
@@ -335,12 +337,12 @@ function traverse(value: unknown, seen: Set<unknown> = new Set()) {
     for (let i = 0; i < value.length; i++) {
       traverse(value[i], seen)
     }
-  } else if (value instanceof Map) {
-    value.forEach((v, key) => {
+  } else if (isMap(value)) {
+    value.forEach((_, key) => {
       // to register mutation dep for existing keys
       traverse(value.get(key), seen)
     })
-  } else if (value instanceof Set) {
+  } else if (isSet(value)) {
     value.forEach(v => {
       traverse(v, seen)
     })
index 2178c5f1ee76cc533c0ee0fc993331136ea7d590..7daeaa5242cd8d201102fd3c7219af834da2c7a4 100644 (file)
@@ -58,9 +58,11 @@ export const hasOwn = (
 ): key is keyof typeof val => hasOwnProperty.call(val, key)
 
 export const isArray = Array.isArray
-export const isSet = (val: any): boolean => {
-  return toRawType(val) === 'Set'
-}
+export const isMap = (val: unknown): val is Map<any, any> =>
+  toTypeString(val) === '[object Map]'
+export const isSet = (val: unknown): val is Set<any> =>
+  toTypeString(val) === '[object Set]'
+
 export const isDate = (val: unknown): val is Date => val instanceof Date
 export const isFunction = (val: unknown): val is Function =>
   typeof val === 'function'
index 2c9b6ab48c751e793ef24658cfa8e72b74de61f0..1d0b69284002c246222953a69c5331cea1eca2eb 100644 (file)
@@ -1,4 +1,4 @@
-import { isArray, isObject, isPlainObject } from './index'
+import { isArray, isMap, isObject, isPlainObject, isSet } from './index'
 
 /**
  * For converting {{ interpolation }} values to displayed strings.
@@ -13,14 +13,14 @@ export const toDisplayString = (val: unknown): string => {
 }
 
 const replacer = (_key: string, val: any) => {
-  if (val instanceof Map) {
+  if (isMap(val)) {
     return {
       [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => {
         ;(entries as any)[`${key} =>`] = val
         return entries
       }, {})
     }
-  } else if (val instanceof Set) {
+  } else if (isSet(val)) {
     return {
       [`Set(${val.size})`]: [...val.values()]
     }