React Native: Optimizing FlatList performance
Tags: reactnative, performance
Published: 2021-09-09 02:29:23

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!** 
```JSX
return (
  <Flatlist
   data={data}
   renderItem={({item}) => <Item item={item} />}
   keyExtractor={(item) => item.id}
  />
);
```
**Instead use this**

```JSX
const renderItem = ({item}) => <Item item={item} />;
const keyExtractor = (item) => item.id;
return (
  <Flatlist
   data={data}
   renderItem={renderItem}
   keyExtractor={keyExtractor}
  />
);
```

### 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.

```JSX
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}
  />
);
``` 
### 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!**
```JSX
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}
  />
);
```

**Do this**
```JSX
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}
  />
);
```

### 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](https://github.com/DylanVann/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](https://reactnative.dev/docs/0.61/optimizing-flatlist-configuration)
[8 ways to optimize React native FlatList performance](https://codingislove.com/optimize-react-native-flatlist-performance/)