React Native’s FlatList performance is great for the most part. However, sometimes it has some drawbacks if the data volume is relatively large. There are many issues and blog posts on the web about how to improve its performance. Here, I’ve tried to put together a relatively uninformative document on the subject.

Just to be clear, there is no silver bullet that will solve every problem. In practical application scenarios, we still need to think about which approach and solution best fits our business needs.

Some relationships and concepts

There were a number of concepts that confused me when I started developing with flatList-related components. So let’s sort them out first:

  • VirtualizedListFlatList is the underlying implementation of FlatList. It is more convenient to use FlatList and SectionList directly. In general, you should only consider using VirtualizedList if you want more flexibility than FlatList (for example, when using immutable data rather than ordinary arrays). Specific can check the official documentVirtualizedlistPart. You can also refer toVirtualized ListThis component provides a list implementation for the React web version. It supports the display of large amounts of data, and automatically recyls the components in the list when the data is displayed.
  • In this article, we’re talking about list Performance, which is a smooth scrolling experience for the user.
  • Memory consumption How much list data occupies Memory is related to the stability of your APP. If the Memory usage is too high, your APP may crash (or be terminated by the operating system).
  • Responsiveness refers to the speed with which applications respond to interactions. For example, if a user clicks on an item in the list and a prompt or redirect page pops up, if the redirect page is slow, we call it weak responsiveness.
  • If the list doesn’t have enough time to render specific list items (such as during a quick scrolling list), you will see the background of the list, which is white.
  • The Window Window here refers to the visual area of the list contents.

Props (Component properties)

Tuning and optimizing component properties is a viable way to optimize FlatList performance. Here are a few ways to tweak this idea.

Set the removeClippedSubviews attribute

You can set the removeClippedSubviews property to true (the default is false) to automatically unmount list item components if they scroll outside of the visible area of the list.

Advantages: This approach is memory friendly, FlatList will render only a portion of the list items, rather than all the data, similar to TableView in iOS.

Disadvantages: If frequent and high speed scrolling is encountered, it will lead to a large number of initialization and unloading actions of list item components. Although the memory usage is reduced, the resulting amount of computation is greatly increased. For some devices with insufficient performance, there will be obvious lag phenomenon, affecting the user experience. If the list item component contains complex initialization operations and data references, it can cause problems or memory leaks. According to the official document, this setting may cause bugs in some cases (for example, contents cannot be displayed). Therefore, use it with caution. (After trying to set removeClippedSubviews to true, test a rendering of a 50-item list, scroll it frequently, and you can see 5-10% CPU usage float up)

maxToRenderPerBatch

Refer to the official VisualizedList API description, which is summarized as follows: The maximum number of incremental renders that can be rendered per batch. The more elements that can be rendered immediately, the faster the fill rate will be, but there may be some loss of responsiveness because each rendered element may participate in or interfere with the response to button click events or other events. The default value for this property is 10.

Advantages: If we set a high value, we will render more items in each batch, which will reduce the probability of a blank area (not rendered in time) being displayed during scrolling.

Cons: Reference shows that a new batch of list items is rendered asynchronously before scrolling into the visual area, and the larger the batch, the more computation is required. This can block the JS thread, preventing the application from responding quickly to user click events. If the list that needs to be rendered in a real application scenario is static and does not need to respond to user interaction, increasing the value of this property is a good choice.

updateCellsBatchingPeriod

The time interval between render batches used for elements with lower render priorities, such as those that are quite far from the screen. The same purpose as maxToRenderPerBatch is to achieve a balance between rendering speed and responsiveness.

This property is in milliseconds; the default is 50 milliseconds.

Advantages: You can work with the maxToRenderPerBatch property to adjust the tempo of your rendering, finding a way to better suit your scene.

Cons: The balance between performance and experience can be tricky, and the choice between performance and visual experience can be a bit tricky.

initialNumToRender

Sets the number of list items to render by default when the list component initializes rendering. Default is 10. If the height of each list item is large, perhaps a smaller value would be more appropriate. Of course, the visual area needs to be filled in, otherwise the user will see a blank area.

windowSize

Sets the maximum number of elements outside the viewable area that can be rendered, in units of viewable length. For example, if the list takes up the entire screen and the windowSize property is set to 21, the render length is 10 screens up and 10 screens down, including the currently visible screen area. Setting windowSize to a smaller value can reduce memory consumption and improve performance, but as you scroll through the list quickly, there is an increased chance that you will encounter unrendered content that will be temporarily replaced by blank blocks.

Advantages: When performance allows, a large number can be set to ensure a smoother user experience and avoid blank areas, such as applications that support only a few relatively new specific devices. If you’re considering compatibility with more devices (such as older models), try to lower this number as much as possible.

Disadvantages: If the value is increased, it will lead to more memory footprint, which can be difficult for some devices. If the value is set too low, it will result in higher frequency calculations.

legacyImplementation

If this property is set to true, it will be implemented based on the ListView. The default value is false.

Advantages: Rendering all items of the list at once, without the additional computational overhead of the VisualizationList component implementation, makes scrolling through the list very smooth.

Disadvantages: If the list content is too large, it occupies too much memory space, triggering a memory warning, and even causing the system to kill the application memory.

disableVirtualization

This property has been cancelled, so we won’t go into it here.


List items

In addition to optimizing list attributes, there are also optimization strategies for rendering list items.

Keep the list item component logic as simple as possible

The more complex the list item component, the slower the rendering. It is important to avoid writing complex business logic in the list item component as much as possible. If your list item component is reused in multiple applications, it is recommended that you create a separate, logically-simplified version of the list for use alone with a large amount of data.

Make components as lightweight as possible

Avoid loading too many resources such as images into list item components. It is recommended to communicate with the design team to minimize the interaction of list items and to achieve more interaction through jumps or other means.

Use shouldComponentUpdate lifecycle

Add update judgment logic to list item components. The React PureComponent implements shouldComponentupdate by default using shallow comparisons of data. Since this implementation requires checking every single one of your attributes, it can be expensive. If we want to achieve better performance, we need to create strict property rules for list item components, checking only for specific properties that can change. If your component is simple enough, you can even do this:

shouldComponentUpdate() {
  return false
}

Copy the code

Use optimized image components

I’m personally used to using @dylanvann’s React-native fast-image component. Each Image in the list item component is an instance of new Image(). The sooner image power completes loaded, the sooner JavaScript threads will release resources.

Using getItemLayout

GetItemLayout is an optional optimization to avoid the overhead of dynamically measuring the size of your content, but only if you know the height of your content in advance. If your row height is fixed, getItemLayout is efficient and easy to use.

getItemLayout = (data, index) = > ({
  length: 70.offset: 70 * index,
  index
})

Copy the code

Using keyExtractor

This function is used to generate a non-repeating key for a given item. The Key allows React to distinguish between individual elements of the same type so that it can determine where they change when refreshing, reducing the cost of re-rendering. If this function is not specified, item.key is extracted as the key value by default. If item.key also does not exist, array subscripts are used.

keyExtractor={item => item.id}
Copy the code

Welcome to follow my public account