DEV Community

Erdenezayaa
Erdenezayaa

Posted on • Edited on

React Native: Optimizing FlatList performance

Flatlist is react-native component should be used for rendering scrollable lists. If you don't optimize well enough, performance starts to drop once dataset gets large. This causes laggy scroll and blank spaces between the list items.

1. Avoid inline functions

Inline functions are recreated every time component renders. This may be okay for some components but can slow performance for flatlists.

Avoid this!

return (
  <Flatlist
   data={data}
   renderItem={({item}) => <Item item={item} />}
   keyExtractor={(item) => item.id}
  />
);
Enter fullscreen mode Exit fullscreen mode

Instead use this

const renderItem = ({item}) => <Item item={item} />;
const keyExtractor = (item) => item.id;
return (
  <Flatlist
   data={data}
   renderItem={renderItem}
   keyExtractor={keyExtractor}
  />
);
Enter fullscreen mode Exit fullscreen mode

2. Provide height value for every item

If you don't provide getItemLayout function as props, Flatlist have to calculate height for every item in the list. By the result of this, sometimes when you scroll fast enough, you will see some gaps in the list. By providing our own getItemLayout function, it won't have to calculate every item's height and the performance will improve.

const ITEM_HEIGHT = 65; // fixed height of item component
const getItemLayout = (data, index) => {
  return {
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  };
};
return (
  <Flatlist
   data={data}
   renderItem={renderItem}
   getItemLayout={getItemLayout}
   keyExtractor={keyExtractor}
  />
);
Enter fullscreen mode Exit fullscreen mode

3. Keep component that renders the list item as light as possible

Don't do any extra work in renderItem function like formatting the data and declaring another function. Also props you pass to renderItem should be only the data that will render in the UI.
In this example, Item component is formatting the date with moment which is heavy js library that should be avoided, formatting a number value right before rendering and getting really big navigation as props every time. All of these, should be avoided to keep the Item component light.
Don't do!

const Item = ({item, navigation}) => {
  const created_at = moment(item.created_at).format('YYY/MM/DD HH:mm');
  const total_value = formatNumber(item.total);
  // it is common to pass navigation instance of react-navigation library, avoid this because navigation props is too big
  const onPressItem = () => {
    navigation.navigate('DetailItem', {item});
  };
  return (
    <View>
     ...
    </View>
  );
}

const renderItem = ({item}) => <Item item={item} navigation={navigation} />;

return (
  <Flatlist
   data={data}
   renderItem={renderItem}
   getItemLayout={getItemLayout}
   keyExtractor={keyExtractor}
  />
);
Enter fullscreen mode Exit fullscreen mode

Do this

const Item = ({item, onItemPress}) => {
  return (
    <View onPress={onItemPress(item)}>
     ...
    </View>
  );
}

// Handle item press event in parent component that has already access to navigation component
const onItemPress = (item) => {
  navigation.navigate('ItemDetail');
};

const renderItem = ({item}) => <Item item={item} navigation={navigation} />;
// do the data formatting and manipulation before the flatlist render
const preparedData = data.map((item) => {
  const created_at = moment(item.created_at).format('YYY/MM/DD HH:mm');
  const total_value = formatNumber(item.total);
  // only return the properties that need to be rendered and leave everything else
  return {
    label: item.label,
    total_value,
    created_at,
  };
});
return (
  <Flatlist
   data={preparedData}
   renderItem={renderItem}
   getItemLayout={getItemLayout}
   keyExtractor={keyExtractor}
  />
);
Enter fullscreen mode Exit fullscreen mode

4. Use Pure Component or Memo

PureComponent re-renders a component by shallow comparing the props and re-renders only if the props have changed. PureComponent is used for class components. React memo is the alternative to PureComponent for functional components.

5. Use cached optimized images

If your list have lots of images, you should use optimal size d, cached images. You can use libraries like react-native-fast-image to implement this. These libraries can do following things.

  • resize images according to device dimensions, therefore reduces the memory consumption.
  • Caches images to memory and storage to better load times.

Keep in mind it works better when you have already optimized images for different sizes of devices.

Conclusion

In my experience, those methods really improved the performance of the Flatlist. I hope you find this helpful. If these methods didn't help, you should checkout the sources I used for this article.

Sources:

Official Documentation for Optimizing Flatlist Configuration
8 ways to optimize React native FlatList performance

Top comments (1)

Collapse
 
fanchenbao profile image
Fanchen Bao • Edited

The usage of getItemLayout is not correct. It should be

const getItemLayout = (data, index) => {
  return {
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * idx, // idx, not data.length
    index,
  };
};
Enter fullscreen mode Exit fullscreen mode

Refer to the usage on the doc.