@@ -11,6 +11,7 @@ import {
1111 Platform ,
1212 FlatList ,
1313 ListRenderItemInfo ,
14+ ViewToken ,
1415} from 'react-native' ;
1516import TabBarItem , { Props as TabBarItemProps } from './TabBarItem' ;
1617import TabBarIndicator , { Props as IndicatorProps } from './TabBarIndicator' ;
@@ -247,6 +248,10 @@ const renderIndicatorDefault = (props: IndicatorProps<Route>) => (
247248
248249const getTestIdDefault = ( { route } : Scene < Route > ) => route . testID ;
249250
251+ // How many items measurements should we update per batch.
252+ // Defaults to 10, since that's whats FlatList is using in initialNumToRender.
253+ const MEASURE_PER_BATCH = 10 ;
254+
250255export default function TabBar < T extends Route > ( {
251256 getLabelText = getLabelTextDefault ,
252257 getAccessible = getAccessibleDefault ,
@@ -279,8 +284,9 @@ export default function TabBar<T extends Route>({
279284} : Props < T > ) {
280285 const [ layout , setLayout ] = React . useState < Layout > ( { width : 0 , height : 0 } ) ;
281286 const [ tabWidths , setTabWidths ] = React . useState < Record < string , number > > ( { } ) ;
282- const flatListRef = React . useRef < FlatList > ( null ) ;
287+ const flatListRef = React . useRef < FlatList | null > ( null ) ;
283288 const isFirst = React . useRef ( true ) ;
289+ const howManyMeasured = React . useRef ( 0 ) ;
284290 const scrollAmount = useAnimatedValue ( 0 ) ;
285291 const measuredTabWidths = React . useRef < Record < string , number > > ( { } ) ;
286292
@@ -298,7 +304,14 @@ export default function TabBar<T extends Route>({
298304
299305 const hasMeasuredTabWidths =
300306 Boolean ( layout . width ) &&
301- routes . every ( ( r ) => typeof tabWidths [ r . key ] === 'number' ) ;
307+ routes
308+ . slice (
309+ 0 ,
310+ routes . length > MEASURE_PER_BATCH
311+ ? howManyMeasured . current
312+ : routes . length
313+ )
314+ . every ( ( r ) => typeof tabWidths [ r . key ] === 'number' ) ;
302315
303316 React . useEffect ( ( ) => {
304317 if ( isFirst . current ) {
@@ -373,13 +386,25 @@ export default function TabBar<T extends Route>({
373386 ? ( e : LayoutChangeEvent ) => {
374387 measuredTabWidths . current [ route . key ] = e . nativeEvent . layout . width ;
375388
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
389+ // If we have more than 10 routes divide updating tabWidths into multiple batches. Here we update only first batch of 10 items.
378390 if (
391+ routes . length > MEASURE_PER_BATCH &&
392+ index === MEASURE_PER_BATCH &&
393+ routes
394+ . slice ( 0 , MEASURE_PER_BATCH )
395+ . every (
396+ ( r ) => typeof measuredTabWidths . current [ r . key ] === 'number'
397+ )
398+ ) {
399+ setTabWidths ( { ...measuredTabWidths . current } ) ;
400+ howManyMeasured . current = MEASURE_PER_BATCH ;
401+ } else if (
379402 routes . every (
380403 ( r ) => typeof measuredTabWidths . current [ r . key ] === 'number'
381404 )
382405 ) {
406+ // When we have measured widths for all of the tabs, we should updates the state
407+ // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
383408 setTabWidths ( { ...measuredTabWidths . current } ) ;
384409 }
385410 }
@@ -494,6 +519,22 @@ export default function TabBar<T extends Route>({
494519 [ scrollAmount ]
495520 ) ;
496521
522+ const handleViewableItemsChanged = React . useCallback (
523+ ( { changed } : { changed : ViewToken [ ] } ) => {
524+ if ( routes . length <= MEASURE_PER_BATCH ) {
525+ return ;
526+ }
527+ // Get next vievable item
528+ const [ item ] = changed ;
529+ const index = item . index || 0 ;
530+ if ( item . isViewable && index >= howManyMeasured . current ) {
531+ setTabWidths ( { ...measuredTabWidths . current } ) ;
532+ howManyMeasured . current += MEASURE_PER_BATCH ;
533+ }
534+ } ,
535+ [ routes . length ]
536+ ) ;
537+
497538 return (
498539 < Animated . View onLayout = { handleLayout } style = { [ styles . tabBar , style ] } >
499540 < Animated . View
@@ -513,6 +554,7 @@ export default function TabBar<T extends Route>({
513554 position,
514555 layout,
515556 navigationState,
557+ visible : hasMeasuredTabWidths ,
516558 jumpTo,
517559 width : isWidthDynamic
518560 ? 'auto'
@@ -535,6 +577,7 @@ export default function TabBar<T extends Route>({
535577 data = { routes as Animated . WithAnimatedValue < T > [ ] }
536578 keyExtractor = { keyExtractor }
537579 horizontal
580+ initialNumToRender = { MEASURE_PER_BATCH }
538581 accessibilityRole = "tablist"
539582 keyboardShouldPersistTaps = "handled"
540583 scrollEnabled = { scrollEnabled }
@@ -549,6 +592,7 @@ export default function TabBar<T extends Route>({
549592 scrollEventThrottle = { 16 }
550593 renderItem = { renderItem }
551594 onScroll = { handleScroll }
595+ onViewableItemsChanged = { handleViewableItemsChanged }
552596 ref = { flatListRef }
553597 testID = { testID }
554598 />
0 commit comments