File tree 4 files changed +42
-10
lines changed
4 files changed +42
-10
lines changed Original file line number Diff line number Diff line change @@ -99,6 +99,33 @@ describe('reactivity/reactive/Array', () => {
99
99
expect ( fn ) . toHaveBeenCalledTimes ( 1 )
100
100
} )
101
101
102
+ test ( 'add existing index on Array should not trigger length dependency' , ( ) => {
103
+ const array = new Array ( 3 )
104
+ const observed = reactive ( array )
105
+ const fn = jest . fn ( )
106
+ effect ( ( ) => {
107
+ fn ( observed . length )
108
+ } )
109
+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
110
+ observed [ 1 ] = 1
111
+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
112
+ } )
113
+
114
+ test ( 'add non-integer prop on Array should not trigger length dependency' , ( ) => {
115
+ const array = new Array ( 3 )
116
+ const observed = reactive ( array )
117
+ const fn = jest . fn ( )
118
+ effect ( ( ) => {
119
+ fn ( observed . length )
120
+ } )
121
+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
122
+ // @ts -ignore
123
+ observed . x = 'x'
124
+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
125
+ observed [ - 1 ] = 'x'
126
+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
127
+ } )
128
+
102
129
describe ( 'Array methods w/ refs' , ( ) => {
103
130
let original : any [ ]
104
131
beforeEach ( ( ) => {
Original file line number Diff line number Diff line change @@ -15,6 +15,7 @@ import {
15
15
isSymbol ,
16
16
hasChanged ,
17
17
isArray ,
18
+ isIntegerKey ,
18
19
extend
19
20
} from '@vue/shared'
20
21
import { isRef } from './ref'
@@ -87,10 +88,7 @@ function createGetter(isReadonly = false, shallow = false) {
87
88
88
89
if ( isRef ( res ) ) {
89
90
// ref unwrapping - does not apply for Array + integer key.
90
- const shouldUnwrap =
91
- ! targetIsArray ||
92
- keyIsSymbol ||
93
- '' + parseInt ( key as string , 10 ) !== key
91
+ const shouldUnwrap = ! targetIsArray || ! isIntegerKey ( key )
94
92
return shouldUnwrap ? res . value : res
95
93
}
96
94
@@ -126,7 +124,10 @@ function createSetter(shallow = false) {
126
124
// in shallow mode, objects are set as-is regardless of reactive or not
127
125
}
128
126
129
- const hadKey = hasOwn ( target , key )
127
+ const hadKey =
128
+ isArray ( target ) && isIntegerKey ( key )
129
+ ? Number ( key ) < target . length
130
+ : hasOwn ( target , key )
130
131
const result = Reflect . set ( target , key , value , receiver )
131
132
// don't trigger if target is something up in the prototype chain of original
132
133
if ( target === toRaw ( receiver ) ) {
Original file line number Diff line number Diff line change 1
1
import { TrackOpTypes , TriggerOpTypes } from './operations'
2
- import { EMPTY_OBJ , isArray } from '@vue/shared'
2
+ import { EMPTY_OBJ , isArray , isIntegerKey } from '@vue/shared'
3
3
4
4
// The main WeakMap that stores {target -> key -> dep} connections.
5
5
// Conceptually, it's easier to think of a dependency as a Dep class
@@ -202,16 +202,17 @@ export function trigger(
202
202
add ( depsMap . get ( key ) )
203
203
}
204
204
// also run for iteration key on ADD | DELETE | Map.SET
205
- const isAddOrDelete =
206
- type === TriggerOpTypes . ADD ||
205
+ const shouldTriggerIteration =
206
+ ( type === TriggerOpTypes . ADD &&
207
+ ( ! isArray ( target ) || isIntegerKey ( key ) ) ) ||
207
208
( type === TriggerOpTypes . DELETE && ! isArray ( target ) )
208
209
if (
209
- isAddOrDelete ||
210
+ shouldTriggerIteration ||
210
211
( type === TriggerOpTypes . SET && target instanceof Map )
211
212
) {
212
213
add ( depsMap . get ( isArray ( target ) ? 'length' : ITERATE_KEY ) )
213
214
}
214
- if ( isAddOrDelete && target instanceof Map ) {
215
+ if ( shouldTriggerIteration && target instanceof Map ) {
215
216
add ( depsMap . get ( MAP_KEY_ITERATE_KEY ) )
216
217
}
217
218
}
Original file line number Diff line number Diff line change @@ -81,6 +81,9 @@ export const toRawType = (value: unknown): string => {
81
81
export const isPlainObject = ( val : unknown ) : val is object =>
82
82
toTypeString ( val ) === '[object Object]'
83
83
84
+ export const isIntegerKey = ( key : unknown ) =>
85
+ isString ( key ) && key [ 0 ] !== '-' && '' + parseInt ( key , 10 ) === key
86
+
84
87
export const isReservedProp = /*#__PURE__*/ makeMap (
85
88
'key,ref,' +
86
89
'onVnodeBeforeMount,onVnodeMounted,' +
You can’t perform that action at this time.
0 commit comments