3
3
type ShallowRef ,
4
4
isReactive ,
5
5
isShallow ,
6
- onScopeDispose ,
7
6
pauseTracking ,
8
7
resetTracking ,
9
8
shallowReadArray ,
@@ -80,12 +79,15 @@ export const createFor = (
80
79
let oldBlocks : ForBlock [ ] = [ ]
81
80
let newBlocks : ForBlock [ ]
82
81
let parent : ParentNode | undefined | null
82
+ // useSelector only
83
+ let currentKey : any
83
84
// TODO handle this in hydration
84
85
const parentAnchor = __DEV__ ? createComment ( 'for' ) : createTextNode ( )
85
86
const frag = new VaporFragment ( oldBlocks )
86
87
const instance = currentInstance !
87
88
const canUseFastRemove = flags & VaporVForFlags . FAST_REMOVE
88
89
const isComponent = flags & VaporVForFlags . IS_COMPONENT
90
+ const selectors : ReturnType < typeof useSelector > [ ] = [ ]
89
91
90
92
if ( __DEV__ && ! instance ) {
91
93
warn ( 'createFor() can only be used inside setup()' )
@@ -113,9 +115,12 @@ export const createFor = (
113
115
}
114
116
} else if ( ! newLength ) {
115
117
// fast path for clearing all
118
+ for ( const selector of selectors ) {
119
+ selector . cleanup ( )
120
+ }
116
121
const doRemove = ! canUseFastRemove
117
122
for ( let i = 0 ; i < oldLength ; i ++ ) {
118
- unmount ( oldBlocks [ i ] , doRemove )
123
+ unmount ( oldBlocks [ i ] , doRemove , false )
119
124
}
120
125
if ( canUseFastRemove ) {
121
126
parent ! . textContent = ''
@@ -230,6 +235,7 @@ export const createFor = (
230
235
const keyRef = needKey ? shallowRef ( key ) : undefined
231
236
const indexRef = needIndex ? shallowRef ( index ) : undefined
232
237
238
+ currentKey = key2
233
239
let nodes : Block
234
240
let scope : EffectScope | undefined
235
241
if ( isComponent ) {
@@ -292,9 +298,18 @@ export const createFor = (
292
298
}
293
299
}
294
300
295
- const unmount = ( { nodes, scope } : ForBlock , doRemove = true ) => {
301
+ const unmount = (
302
+ { nodes, scope, key } : ForBlock ,
303
+ doRemove = true ,
304
+ doDeregister = true ,
305
+ ) => {
296
306
scope && scope . stop ( )
297
307
doRemove && removeBlock ( nodes , parent ! )
308
+ if ( doDeregister ) {
309
+ for ( const selector of selectors ) {
310
+ selector . deregister ( key )
311
+ }
312
+ }
298
313
}
299
314
300
315
if ( flags & VaporVForFlags . ONCE ) {
@@ -307,7 +322,69 @@ export const createFor = (
307
322
insert ( frag , _insertionParent , _insertionAnchor )
308
323
}
309
324
325
+ // @ts -expect-error
326
+ frag . useSelector = useSelector
327
+
310
328
return frag
329
+
330
+ function useSelector ( getActiveKey : ( ) => any ) : {
331
+ register : ( key : any , cb : ( ) => void ) => void
332
+ deregister : ( key : any ) => void
333
+ cleanup : ( ) => void
334
+ } {
335
+ let operMap = new Map < any , ( ( ) => void ) | ( ( ) => void ) [ ] > ( )
336
+ let activeKey : any
337
+
338
+ watch ( getActiveKey , newValue => {
339
+ do {
340
+ if ( activeKey !== undefined ) {
341
+ const opers = operMap . get ( activeKey )
342
+ if ( Array . isArray ( opers ) ) {
343
+ for ( const oper of opers ) {
344
+ oper ( )
345
+ }
346
+ } else if ( opers !== undefined ) {
347
+ opers ( )
348
+ }
349
+ }
350
+ if ( activeKey !== newValue ) {
351
+ activeKey = newValue
352
+ continue
353
+ }
354
+ break
355
+ } while ( true )
356
+ } )
357
+
358
+ const res = { register, deregister, cleanup }
359
+ selectors . push ( res )
360
+ return res
361
+
362
+ function cleanup ( ) {
363
+ operMap = new Map ( )
364
+ }
365
+
366
+ function register ( oper : ( ) => void ) {
367
+ oper ( )
368
+ let opers = operMap . get ( currentKey )
369
+ if ( opers !== undefined ) {
370
+ if ( Array . isArray ( opers ) ) {
371
+ opers . push ( oper )
372
+ } else {
373
+ opers = [ opers , oper ]
374
+ operMap . set ( currentKey , opers )
375
+ }
376
+ } else {
377
+ operMap . set ( currentKey , oper )
378
+ if ( activeKey === undefined ) {
379
+ activeKey = getActiveKey ( )
380
+ }
381
+ }
382
+ }
383
+
384
+ function deregister ( key : any ) {
385
+ operMap . delete ( key )
386
+ }
387
+ }
311
388
}
312
389
313
390
export function createForSlots (
@@ -390,74 +467,3 @@ export function getRestElement(val: any, keys: string[]): any {
390
467
export function getDefaultValue ( val : any , defaultVal : any ) : any {
391
468
return val === undefined ? defaultVal : val
392
469
}
393
-
394
- export function useSelectorPattern (
395
- getActiveKey : ( ) => any ,
396
- source : ( ) => any [ ] ,
397
- ) : {
398
- register : ( key : any , cb : ( ) => void ) => void
399
- } {
400
- let mapVersion = 1
401
- let operMap = new Map < any , ( ( ) => void ) [ ] > ( )
402
- let activeOpers : ( ( ) => void ) [ ] | undefined
403
-
404
- watch ( source , newValue => {
405
- if ( Array . isArray ( newValue ) && ! newValue . length ) {
406
- operMap = new Map ( )
407
- activeOpers = undefined
408
- mapVersion ++
409
- }
410
- } )
411
- watch ( getActiveKey , newValue => {
412
- if ( activeOpers !== undefined ) {
413
- for ( const oper of activeOpers ) {
414
- oper ( )
415
- }
416
- }
417
- activeOpers = operMap . get ( newValue )
418
- if ( activeOpers !== undefined ) {
419
- for ( const oper of activeOpers ) {
420
- oper ( )
421
- }
422
- }
423
- } )
424
-
425
- return { register }
426
-
427
- function register ( key : any , oper : ( ) => void ) {
428
- oper ( )
429
- let opers = operMap . get ( key )
430
- if ( opers !== undefined ) {
431
- opers . push ( oper )
432
- } else {
433
- opers = [ oper ]
434
- operMap . set ( key , opers )
435
- if ( getActiveKey ( ) === key ) {
436
- activeOpers = opers
437
- }
438
- }
439
- const currentMapVersion = mapVersion
440
- onScopeDispose ( ( ) => {
441
- if ( currentMapVersion === mapVersion ) {
442
- deregister ( key , oper )
443
- }
444
- } )
445
- }
446
-
447
- function deregister ( key : any , oper : ( ) => void ) {
448
- const opers = operMap . get ( key )
449
- if ( opers !== undefined ) {
450
- if ( opers . length === 1 ) {
451
- operMap . delete ( key )
452
- if ( activeOpers === opers ) {
453
- activeOpers = undefined
454
- }
455
- } else {
456
- const index = opers . indexOf ( oper )
457
- if ( index >= 0 ) {
458
- opers . splice ( index , 1 )
459
- }
460
- }
461
- }
462
- }
463
- }
0 commit comments