]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): Array methods relying on identity should work with raw values
authorEvan You <yyx990803@gmail.com>
Thu, 23 Jan 2020 18:42:31 +0000 (13:42 -0500)
committerEvan You <yyx990803@gmail.com>
Thu, 23 Jan 2020 18:42:31 +0000 (13:42 -0500)
packages/reactivity/__tests__/reactive.spec.ts
packages/reactivity/src/baseHandlers.ts

index 62913e67063d29fe847bfb7b5f66aaa0570bca4c..9db682f897318e3bc3e9344341327c28f4486d92 100644 (file)
@@ -44,6 +44,27 @@ describe('reactivity/reactive', () => {
     expect(clone[0]).toBe(observed[0])
   })
 
+  test('Array identity methods should work with raw values', () => {
+    const raw = {}
+    const arr = reactive([{}, {}])
+    arr.push(raw)
+    expect(arr.indexOf(raw)).toBe(2)
+    expect(arr.indexOf(raw, 3)).toBe(-1)
+    expect(arr.includes(raw)).toBe(true)
+    expect(arr.includes(raw, 3)).toBe(false)
+    expect(arr.lastIndexOf(raw)).toBe(2)
+    expect(arr.lastIndexOf(raw, 1)).toBe(-1)
+
+    // should work also for the observed version
+    const observed = arr[2]
+    expect(arr.indexOf(observed)).toBe(2)
+    expect(arr.indexOf(observed, 3)).toBe(-1)
+    expect(arr.includes(observed)).toBe(true)
+    expect(arr.includes(observed, 3)).toBe(false)
+    expect(arr.lastIndexOf(observed)).toBe(2)
+    expect(arr.lastIndexOf(observed, 1)).toBe(-1)
+  })
+
   test('nested reactives', () => {
     const original = {
       nested: {
index 307697055237fa376ab110d04006289b6b93854c..cee6588988a2cb76e41436f4fd3b9270ef321d08 100644 (file)
@@ -2,7 +2,7 @@ import { reactive, readonly, toRaw } from './reactive'
 import { TrackOpTypes, TriggerOpTypes } from './operations'
 import { track, trigger, ITERATE_KEY } from './effect'
 import { LOCKED } from './lock'
-import { isObject, hasOwn, isSymbol, hasChanged } from '@vue/shared'
+import { isObject, hasOwn, isSymbol, hasChanged, isArray } from '@vue/shared'
 import { isRef } from './ref'
 
 const builtInSymbols = new Set(
@@ -15,8 +15,21 @@ const get = /*#__PURE__*/ createGetter()
 const readonlyGet = /*#__PURE__*/ createGetter(true)
 const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)
 
+const arrayIdentityInstrumentations: Record<string, Function> = {}
+;['includes', 'indexOf', 'lastIndexOf'].forEach(key => {
+  arrayIdentityInstrumentations[key] = function(
+    value: unknown,
+    ...args: any[]
+  ): any {
+    return toRaw(this)[key](toRaw(value), ...args)
+  }
+})
+
 function createGetter(isReadonly = false, shallow = false) {
   return function get(target: object, key: string | symbol, receiver: object) {
+    if (isArray(target) && hasOwn(arrayIdentityInstrumentations, key)) {
+      return Reflect.get(arrayIdentityInstrumentations, key, receiver)
+    }
     const res = Reflect.get(target, key, receiver)
     if (isSymbol(key) && builtInSymbols.has(key)) {
       return res