@@ -11,6 +11,7 @@ import {
11
11
Platform ,
12
12
FlatList ,
13
13
ListRenderItemInfo ,
14
+ ViewToken ,
14
15
} from 'react-native' ;
15
16
import TabBarItem , { Props as TabBarItemProps } from './TabBarItem' ;
16
17
import TabBarIndicator , { Props as IndicatorProps } from './TabBarIndicator' ;
@@ -247,6 +248,8 @@ const renderIndicatorDefault = (props: IndicatorProps<Route>) => (
247
248
248
249
const getTestIdDefault = ( { route } : Scene < Route > ) => route . testID ;
249
250
251
+ const MEASURE_PER_BATCH = 10 ;
252
+
250
253
export default function TabBar < T extends Route > ( {
251
254
getLabelText = getLabelTextDefault ,
252
255
getAccessible = getAccessibleDefault ,
@@ -279,8 +282,9 @@ export default function TabBar<T extends Route>({
279
282
} : Props < T > ) {
280
283
const [ layout , setLayout ] = React . useState < Layout > ( { width : 0 , height : 0 } ) ;
281
284
const [ tabWidths , setTabWidths ] = React . useState < Record < string , number > > ( { } ) ;
282
- const flatListRef = React . useRef < FlatList > ( null ) ;
285
+ const flatListRef = React . useRef < FlatList | null > ( null ) ;
283
286
const isFirst = React . useRef ( true ) ;
287
+ const measuredTabWidhtsCount = React . useRef ( 0 ) ;
284
288
const scrollAmount = useAnimatedValue ( 0 ) ;
285
289
const measuredTabWidths = React . useRef < Record < string , number > > ( { } ) ;
286
290
@@ -298,7 +302,14 @@ export default function TabBar<T extends Route>({
298
302
299
303
const hasMeasuredTabWidths =
300
304
Boolean ( layout . width ) &&
301
- routes . every ( ( r ) => typeof tabWidths [ r . key ] === 'number' ) ;
305
+ routes
306
+ . slice (
307
+ 0 ,
308
+ routes . length > MEASURE_PER_BATCH
309
+ ? measuredTabWidhtsCount . current
310
+ : routes . length
311
+ )
312
+ . every ( ( r ) => typeof tabWidths [ r . key ] === 'number' ) ;
302
313
303
314
React . useEffect ( ( ) => {
304
315
if ( isFirst . current ) {
@@ -373,13 +384,25 @@ export default function TabBar<T extends Route>({
373
384
? ( e : LayoutChangeEvent ) => {
374
385
measuredTabWidths . current [ route . key ] = e . nativeEvent . layout . width ;
375
386
376
- // When we have measured widths for all of the tabs, we should updates the state
377
- // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
387
+ // If we have more than 10 routes divide updating tabWidths into multiple batches. Here we update only first batch of 10 items.
378
388
if (
389
+ routes . length > MEASURE_PER_BATCH &&
390
+ index === MEASURE_PER_BATCH &&
391
+ routes
392
+ . slice ( 0 , MEASURE_PER_BATCH )
393
+ . every (
394
+ ( r ) => typeof measuredTabWidths . current [ r . key ] === 'number'
395
+ )
396
+ ) {
397
+ setTabWidths ( { ...measuredTabWidths . current } ) ;
398
+ measuredTabWidhtsCount . current = MEASURE_PER_BATCH ;
399
+ } else if (
379
400
routes . every (
380
401
( r ) => typeof measuredTabWidths . current [ r . key ] === 'number'
381
402
)
382
403
) {
404
+ // When we have measured widths for all of the tabs, we should updates the state
405
+ // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
383
406
setTabWidths ( { ...measuredTabWidths . current } ) ;
384
407
}
385
408
}
@@ -494,6 +517,22 @@ export default function TabBar<T extends Route>({
494
517
[ scrollAmount ]
495
518
) ;
496
519
520
+ const handleViewableItemsChanged = React . useCallback (
521
+ ( { changed } : { changed : ViewToken [ ] } ) => {
522
+ if ( routes . length <= MEASURE_PER_BATCH ) {
523
+ return ;
524
+ }
525
+ // Get next vievable item
526
+ const [ item ] = changed ;
527
+ const index = item . index || 0 ;
528
+ if ( item . isViewable && index >= measuredTabWidhtsCount . current ) {
529
+ setTabWidths ( { ...measuredTabWidths . current } ) ;
530
+ measuredTabWidhtsCount . current += MEASURE_PER_BATCH ;
531
+ }
532
+ } ,
533
+ [ routes . length ]
534
+ ) ;
535
+
497
536
return (
498
537
< Animated . View onLayout = { handleLayout } style = { [ styles . tabBar , style ] } >
499
538
< Animated . View
@@ -513,6 +552,7 @@ export default function TabBar<T extends Route>({
513
552
position,
514
553
layout,
515
554
navigationState,
555
+ hasMeasuredTabWidths,
516
556
jumpTo,
517
557
width : isWidthDynamic
518
558
? 'auto'
@@ -549,6 +589,7 @@ export default function TabBar<T extends Route>({
549
589
scrollEventThrottle = { 16 }
550
590
renderItem = { renderItem }
551
591
onScroll = { handleScroll }
592
+ onViewableItemsChanged = { handleViewableItemsChanged }
552
593
ref = { flatListRef }
553
594
testID = { testID }
554
595
/>
0 commit comments