javascriptreact-nativeshopifyreact-native-flatlistflash-list

FlashList is taking too long in first render compared to FlatList


Current behavior

FlashList is taking too much time on first render compared to FlatList: Flashlit is taking around 3 seconds Flatlist is taking 300ms

Expected behavior

FlashList should take not much time on first render. for FlatList change only FlashList to Flatlist and remove estimatedItemSize and estimatedListSize

To Reproduce

this is my code:

import React from 'react';
import { Dimensions, FlatList } from 'react-native';
import { NewCarCard } from 'features/cars/new-cars/new-car-card';
import { Line } from 'ui/dividers/line';
import { useNewCars } from 'features/cars/new-cars/hooks/use-new-cars';
import { NewCarsVerticalListShimmer } from 'features/cars/new-cars/shimmers/new-cars-vertical-list.shimmer';

const deviceWidth = Dimensions.get('window').width;
const deviceHeight = Dimensions.get('window').height;

interface Props {
  onPress: () => void;
  scrollEnabled: boolean;
}

export function NewCarsVerticalList(props: Props) {
  const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = useNewCars();
  const newCarsFlatted = data?.pages.map(page => page.data.data.items).flat();
  const loadNext = React.useCallback(() => {
    if (hasNextPage && !isFetchingNextPage) {
      fetchNextPage();
    }
  }, [hasNextPage, isFetchingNextPage, fetchNextPage]);

  const renderItem = ({ item }) => {
    return (
      <React.Fragment>
        <NewCarCard newCar={item} onPress={props.onPress} />
        <Line />
      </React.Fragment>
    );
  };
  const renderListFooter = () => {
    if (isFetchingNextPage) {
      return (
        // Show shimmer when isFetchingNextPage is true
        <>
          <NewCarsVerticalListShimmer />
          <NewCarsVerticalListShimmer />
        </>
      );
    }
    return null;
  };

  return (
    <FlashList
      scrollEnabled={props.scrollEnabled || false}
      data={newCarsFlatted}
      showsVerticalScrollIndicator={false}
      estimatedItemSize={deviceHeight * 0.45}
      estimatedListSize={{
        height: deviceHeight * 0.45 * newCarsFlatted.length,
        width: Dimensions.get('screen').width,
      }}
      renderItem={({ item }) => renderItem({ item })}
      keyExtractor={item => item?.id} // Make sure to use a string for the key
      onEndReached={loadNext}
      onEndReachedThreshold={0.7}
      ListFooterComponent={renderListFooter}
    />
  );
}

export default React.memo(NewCarsVerticalList);

Platform:

Environment


Solution

  • The right answer was: estimatedListSize should refer to number of possible available items in the screen and not the whole dataset

    estimatedListSize={{
            height: deviceHeight * 0.45 * newCarsFlatted.length,
            width: Dimensions.get('screen').width,
          }}
    

    In my case only 2 elements of the list could be shown in screen.