|
|
@@ -8,7 +8,13 @@ import {
|
|
|
reactiveMap
|
|
|
} from './reactive'
|
|
|
import { TrackOpTypes, TriggerOpTypes } from './operations'
|
|
|
-import { track, trigger, ITERATE_KEY } from './effect'
|
|
|
+import {
|
|
|
+ track,
|
|
|
+ trigger,
|
|
|
+ ITERATE_KEY,
|
|
|
+ pauseTracking,
|
|
|
+ enableTracking
|
|
|
+} from './effect'
|
|
|
import {
|
|
|
isObject,
|
|
|
hasOwn,
|
|
|
@@ -32,22 +38,36 @@ const readonlyGet = /*#__PURE__*/ createGetter(true)
|
|
|
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)
|
|
|
|
|
|
const arrayInstrumentations: Record<string, Function> = {}
|
|
|
+// instrument identity-sensitive Array methods to account for possible reactive
|
|
|
+// values
|
|
|
;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
|
|
|
+ const method = Array.prototype[key] as any
|
|
|
arrayInstrumentations[key] = function(this: unknown[], ...args: unknown[]) {
|
|
|
const arr = toRaw(this)
|
|
|
for (let i = 0, l = this.length; i < l; i++) {
|
|
|
track(arr, TrackOpTypes.GET, i + '')
|
|
|
}
|
|
|
// we run the method using the original args first (which may be reactive)
|
|
|
- const res = (arr[key] as any)(...args)
|
|
|
+ const res = method.apply(arr, args)
|
|
|
if (res === -1 || res === false) {
|
|
|
// if that didn't work, run it again using raw values.
|
|
|
- return (arr[key] as any)(...args.map(toRaw))
|
|
|
+ return method.apply(arr, args.map(toRaw))
|
|
|
} else {
|
|
|
return res
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
+// instrument length-altering mutation methods to avoid length being tracked
|
|
|
+// which leads to infinite loops in some cases (#2137)
|
|
|
+;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
|
|
|
+ const method = Array.prototype[key] as any
|
|
|
+ arrayInstrumentations[key] = function(this: unknown[], ...args: unknown[]) {
|
|
|
+ pauseTracking()
|
|
|
+ const res = method.apply(this, args)
|
|
|
+ enableTracking()
|
|
|
+ return res
|
|
|
+ }
|
|
|
+})
|
|
|
|
|
|
function createGetter(isReadonly = false, shallow = false) {
|
|
|
return function get(target: Target, key: string | symbol, receiver: object) {
|