fix(reactivity): Array methods relying on identity should work with raw values

This commit is contained in:
Evan You 2020-01-23 13:42:31 -05:00
parent 3919c7840d
commit aefb7d282e
2 changed files with 35 additions and 1 deletions

View 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: {

View 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