@@ -46,12 +46,12 @@ export interface ReactiveEffectOptions {
46
46
47
47
export type DebuggerEvent = {
48
48
effect : ReactiveEffect
49
+ } & DebuggerEventExtraInfo
50
+
51
+ export type DebuggerEventExtraInfo = {
49
52
target : object
50
53
type : TrackOpTypes | TriggerOpTypes
51
54
key : any
52
- } & DebuggerEventExtraInfo
53
-
54
- export interface DebuggerEventExtraInfo {
55
55
newValue ?: any
56
56
oldValue ?: any
57
57
oldTarget ?: Map < any , any > | Set < any >
@@ -111,7 +111,8 @@ function createReactiveEffect<T = any>(
111
111
} finally {
112
112
effectStack . pop ( )
113
113
resetTracking ( )
114
- activeEffect = effectStack [ effectStack . length - 1 ]
114
+ const n = effectStack . length
115
+ activeEffect = n > 0 ? effectStack [ n - 1 ] : undefined
115
116
}
116
117
}
117
118
} as ReactiveEffect
@@ -154,7 +155,7 @@ export function resetTracking() {
154
155
}
155
156
156
157
export function track ( target : object , type : TrackOpTypes , key : unknown ) {
157
- if ( ! shouldTrack || activeEffect === undefined ) {
158
+ if ( ! isTracking ( ) ) {
158
159
return
159
160
}
160
161
let depsMap = targetMap . get ( target )
@@ -165,16 +166,34 @@ export function track(target: object, type: TrackOpTypes, key: unknown) {
165
166
if ( ! dep ) {
166
167
depsMap . set ( key , ( dep = new Set ( ) ) )
167
168
}
168
- if ( ! dep . has ( activeEffect ) ) {
169
- dep . add ( activeEffect )
170
- activeEffect . deps . push ( dep )
171
- if ( __DEV__ && activeEffect . options . onTrack ) {
172
- activeEffect . options . onTrack ( {
173
- effect : activeEffect ,
174
- target,
175
- type,
176
- key
177
- } )
169
+
170
+ const eventInfo = __DEV__
171
+ ? { effect : activeEffect , target, type, key }
172
+ : undefined
173
+
174
+ trackEffects ( dep , eventInfo )
175
+ }
176
+
177
+ export function isTracking ( ) {
178
+ return shouldTrack && activeEffect !== undefined
179
+ }
180
+
181
+ export function trackEffects (
182
+ dep : Set < ReactiveEffect > ,
183
+ debuggerEventExtraInfo ?: DebuggerEventExtraInfo
184
+ ) {
185
+ if ( ! dep . has ( activeEffect ! ) ) {
186
+ dep . add ( activeEffect ! )
187
+ activeEffect ! . deps . push ( dep )
188
+ if ( __DEV__ && activeEffect ! . options . onTrack ) {
189
+ activeEffect ! . options . onTrack (
190
+ Object . assign (
191
+ {
192
+ effect : activeEffect !
193
+ } ,
194
+ debuggerEventExtraInfo
195
+ )
196
+ )
178
197
}
179
198
}
180
199
}
@@ -193,73 +212,88 @@ export function trigger(
193
212
return
194
213
}
195
214
196
- const effects = new Set < ReactiveEffect > ( )
197
- const add = ( effectsToAdd : Set < ReactiveEffect > | undefined ) => {
198
- if ( effectsToAdd ) {
199
- effectsToAdd . forEach ( effect => {
200
- if ( effect !== activeEffect || effect . allowRecurse ) {
201
- effects . add ( effect )
202
- }
203
- } )
204
- }
205
- }
206
-
215
+ let sets : DepSets = [ ]
207
216
if ( type === TriggerOpTypes . CLEAR ) {
208
217
// collection being cleared
209
218
// trigger all effects for target
210
- depsMap . forEach ( add )
219
+ sets = [ ... depsMap . values ( ) ]
211
220
} else if ( key === 'length' && isArray ( target ) ) {
212
221
depsMap . forEach ( ( dep , key ) => {
213
222
if ( key === 'length' || key >= ( newValue as number ) ) {
214
- add ( dep )
223
+ sets . push ( dep )
215
224
}
216
225
} )
217
226
} else {
218
227
// schedule runs for SET | ADD | DELETE
219
228
if ( key !== void 0 ) {
220
- add ( depsMap . get ( key ) )
229
+ sets . push ( depsMap . get ( key ) )
221
230
}
222
231
223
232
// also run for iteration key on ADD | DELETE | Map.SET
224
233
switch ( type ) {
225
234
case TriggerOpTypes . ADD :
226
235
if ( ! isArray ( target ) ) {
227
- add ( depsMap . get ( ITERATE_KEY ) )
236
+ sets . push ( depsMap . get ( ITERATE_KEY ) )
228
237
if ( isMap ( target ) ) {
229
- add ( depsMap . get ( MAP_KEY_ITERATE_KEY ) )
238
+ sets . push ( depsMap . get ( MAP_KEY_ITERATE_KEY ) )
230
239
}
231
240
} else if ( isIntegerKey ( key ) ) {
232
241
// new index added to array -> length changes
233
- add ( depsMap . get ( 'length' ) )
242
+ sets . push ( depsMap . get ( 'length' ) )
234
243
}
235
244
break
236
245
case TriggerOpTypes . DELETE :
237
246
if ( ! isArray ( target ) ) {
238
- add ( depsMap . get ( ITERATE_KEY ) )
247
+ sets . push ( depsMap . get ( ITERATE_KEY ) )
239
248
if ( isMap ( target ) ) {
240
- add ( depsMap . get ( MAP_KEY_ITERATE_KEY ) )
249
+ sets . push ( depsMap . get ( MAP_KEY_ITERATE_KEY ) )
241
250
}
242
251
}
243
252
break
244
253
case TriggerOpTypes . SET :
245
254
if ( isMap ( target ) ) {
246
- add ( depsMap . get ( ITERATE_KEY ) )
255
+ sets . push ( depsMap . get ( ITERATE_KEY ) )
247
256
}
248
257
break
249
258
}
250
259
}
251
260
261
+ const eventInfo = __DEV__
262
+ ? { target, type, key, newValue, oldValue, oldTarget }
263
+ : undefined
264
+ triggerMultiEffects ( sets , eventInfo )
265
+ }
266
+
267
+ type DepSets = ( Dep | undefined ) [ ]
268
+
269
+ export function triggerMultiEffects (
270
+ depSets : DepSets ,
271
+ debuggerEventExtraInfo ?: DebuggerEventExtraInfo
272
+ ) {
273
+ if ( depSets . length === 1 ) {
274
+ if ( depSets [ 0 ] ) {
275
+ triggerEffects ( depSets [ 0 ] , debuggerEventExtraInfo )
276
+ }
277
+ } else {
278
+ const sets = depSets . filter ( s => ! ! s ) as Dep [ ]
279
+ triggerEffects ( concatSets ( sets ) , debuggerEventExtraInfo )
280
+ }
281
+ }
282
+
283
+ function concatSets < T > ( sets : Set < T > [ ] ) : Set < T > {
284
+ const all = ( [ ] as T [ ] ) . concat ( ...sets . map ( s => [ ...s ! ] ) )
285
+ return new Set ( all )
286
+ }
287
+
288
+ export function triggerEffects (
289
+ dep : Dep ,
290
+ debuggerEventExtraInfo ?: DebuggerEventExtraInfo
291
+ ) {
252
292
const run = ( effect : ReactiveEffect ) => {
253
293
if ( __DEV__ && effect . options . onTrigger ) {
254
- effect . options . onTrigger ( {
255
- effect,
256
- target,
257
- key,
258
- type,
259
- newValue,
260
- oldValue,
261
- oldTarget
262
- } )
294
+ effect . options . onTrigger (
295
+ Object . assign ( { effect } , debuggerEventExtraInfo )
296
+ )
263
297
}
264
298
if ( effect . options . scheduler ) {
265
299
effect . options . scheduler ( effect )
@@ -268,5 +302,10 @@ export function trigger(
268
302
}
269
303
}
270
304
271
- effects . forEach ( run )
305
+ const immutableDeps = [ ...dep ]
306
+ immutableDeps . forEach ( effect => {
307
+ if ( effect !== activeEffect || effect . allowRecurse ) {
308
+ run ( effect )
309
+ }
310
+ } )
272
311
}
0 commit comments