Skip to main content

Command Palette

Search for a command to run...

Optimizing List Performance in React Native: Best Practices and Techniques

Techniques to Streamline Your React Native Lists

Updated
โ€ข6 min read
Optimizing List Performance in React Native: Best Practices and Techniques
A

๐Ÿš€ Software Engineer | Problem-Solving Enthusiast ๐Ÿ’ก | Deep Thinker ๐Ÿง  | Passionate Learner ๐Ÿ“š | Turning code into solutions, one algorithm at a time. #Techie

Lists are ubiquitous; they display our contacts, our news feeds, search results, and much more.

However, an unoptimized list can lead to choppy scrolling, slow loading times, and a frustrated user.

In this guide, let's dive into React Native and offer you straightforward strategies to boost your list performance, ensuring a smooth experience for your app users.

Don't use Array.map() method to render large lists.

When you use array.map to render a large list of items, React Native attempts to render every single item at once.

For a large dataset, this means a lot of processing is required upfront.

Instead, using components like FlatList or SectionList provides optimized rendering by only processing and displaying the items that fit on the screen, known as "windowing".

These components are tailored to handle large datasets efficiently, improving performance and responsiveness.

Use Specialized Components.

FlatList and SectionList are components provided by React Native to efficiently display lists of data.

They're built on top of the VirtualizedList component, which helps optimize memory usage and reduce the number of expensive calls to the render method by only rendering items that are currently visible on the screen.

FlatList is primarily used for rendering a straightforward list of items.

FlatList also offers built-in functionalities like pull-to-refresh and on-the-end-reached (often used for infinite scrolling).

Here's how to use FlatList:

<FlatList
  data={myDataArray}
  renderItem={({ item }) => <Text>{item.title}</Text>}
  keyExtractor={item => item.id.toString()}
/>

SectionList is specifically designed to render lists of grouped data, where each group (or section) can have its header and footer.

Here's how to use SectionList:

<SectionList
  sections={[
    { title: 'A', data: ['Apple', 'Aardvark'] },
    { title: 'B', data: ['Banana', 'Baboon'] },
    // ... (more sections)
  ]}
  renderItem={({ item }) => <Text>{item}</Text>}
  renderSectionHeader={({ section }) => <Text>{section.title}</Text>}
  keyExtractor={(item, index) => index.toString()}
/>

Use keyExtractor prop in FlatList/SectionList wisely.

The keyExtractor prop in FlatList and SectionList assigns a unique "key" to every item, helping React handle item updates efficiently.

It's used to uniquely identify each item in the list.

Without a unique key, React will have a harder time determining which items have changed, leading to unnecessary rendering of items.

Having a unique key for each item allows React to optimize re-rendering and boost the performance of the app.

Here's a deeper look:

The keyExtractor prop is a function that takes two parameters:

  • the individual item from the data source.

  • the index of the item in the data source.

The function should return a unique string for each item.

For example,

Let's say you have a list of user objects, each with a unique id. You can use the id as the unique key for each item:

<FlatList
  data={users}
  renderItem={({ item }) => <Text>{item.name}</Text>}
  keyExtractor={item => item.id.toString()}
/>

Load only limited items at once by using Infinite scrolling.

When dealing with large datasets or content feeds, loading all data at once can slow down the initial rendering of a webpage or app.

It can consume more memory, particularly problematic for devices with limited resources.

It is better to load content progressively as the user scrolls down. It enhances user experience by loading data on-demand, making initial rendering faster and consuming fewer resources initially.

React Native's FlatList component makes implementing infinite scrolling straightforward by using the onEndReached prop.

The onEndReached prop in FlatList takes a callback that is triggered once the user has scrolled to a certain point near the end of the items currently displayed.

Implementing Infinite Scrolling:

  1. Initial Data: Start with an initial set of data that you load into your FlatList.

  2. Detect End: Using the onEndReached prop, detect when the user is close to the end of the current list.

  3. Fetch More Data: When the end is detected, fetch more data. This usually involves making an API call to retrieve the next set of data.

  4. Update State: Once you've retrieved the additional data, update your state to append the new data to the existing list.

  5. Rerender: React Native will take care of rerendering your FlatList with the new items.

For example,

const [data, setData] = useState(initialData);

const fetchMoreData = async () => {
    const newData = await fetchDataFunction();
    setData(prevData => [...prevData, ...newData]);
};

return (
    <FlatList
        data={data}
        renderItem={({ item }) => <Text>{item.name}</Text>}
        keyExtractor={item => item.id.toString()}
        onEndReached={fetchMoreData}
        onEndReachedThreshold={0.5}
    />
);

Use Shopify's FlashList Component.

@shopify/flash-list is a React Native list library that offers fast and performant lists. It is designed to be a drop-in replacement for React Native's FlatList component.

FlashList is optimized for performance on both iOS and Android, and it performs well even on low-end Android devices. It runs 10 times faster on the JS thread and 5 times faster on the UI thread than FlatList.

It also offers a better user experience by eliminating blank cells that sometimes span the whole screen.

You can start using FlashList by simply replacing the FlatList component and adding estimatedItemSize prop.

<FlashList
  data={myDataArray}
  renderItem={({ item }) => <Text>{item.title}</Text>}
  keyExtractor={item => item.id.toString()}
  estimatedItemSize={100}
/>

This prop allows you to provide an estimated size for each item in the list. It helps FlashList optimize the rendering and scrolling performance by pre-calculating the item sizes.

Memoize list item components.

If the rendering of each list item is expensive or if the list updates frequently, unnecessary re-renders can bog down performance.

Memoization is a technique to optimize expensive function calls by caching the results of these calls based on the inputs.

When dealing with lists, such as those rendered by FlatList, memoizing the renderItem component can offer significant performance improvements, especially when dealing with large lists or complex item render logic.

You can use React.memo higher-order component for memoizing rendered output of the list item component ensuring that the component doesn't re-render if its props haven't changed.

const MemoizedItem = React.memo(function MyItem({ item }) {
  return <Text>{item.name}</Text>;
});

<FlatList
  data={data}
  renderItem={({ item }) => <MemoizedItem item={item} />}
  keyExtractor={item => item.id.toString()}
/>

Or by using the useMemo hook if there are some derived data or calculations within the renderItem.

const renderItem = ({ item }) => {
  const computedValue = useMemo(
    () => expensiveCalculation(item.value),
    [item.value],
  );
  return <Text>{computedValue}</Text>;
};

Use Profiler and performance measuring tools.

There can be many reasons why your React Native app which displays lists can have poor performance, which may have little to do with rendering the lists.

Using a profiler to monitor and analyze your React Native application is crucial for identifying performance bottlenecks and enhancing the overall user experience.

Here are some notable performance monitoring tools for React Native:

  1. Flipper

  2. React DevTools

  3. React Native Debugger

  4. Android Studio Profiler

  5. XCode Instruments

  6. Reactotron

By using the right tools and strategies, you can ensure apps run smoothly and efficiently.

Remember, in mobile apps, every moment of speed counts.