How to avoid rendering non-changing items on React Native FlatLists
After creating some sections with FlatList components to render a list of items, I realised that the sections containing this kind of list with a lot of items, weren’t running smooth on slow devices. In fact, it was lagging a lot while trying to open the section container, and clicking on an item to trigger its action took a while.
After investigating what was happening, the team discovered that the cause of the slow performance was that all the FlatList options were rerendered when just one of them changed its state. Let’s see how we managed to only rerender the option whose state changed and don’t bother the unaffected ones.
FlatList basic example: All items rerender by default
Originally, our components that use FlatList looked something like this:
On the SelectOptions
file, we have our FlatList that calls to the renderOptionItem
method defined on this same file. We’re checking if the option has been selected or unselected, depending on the selection state, we apply different styles.
If we check renderOptionItem
method with a console.log
, we’ll see that if one option changed its state, this option rerendered (ok!) as well as the rest of options (nope!).
Moving renderOptionItem to a new component
The first thing we need to do is to moverenderOptionItem
to a new component, and to call it from SelectOptions
:
OptionItem
has been created as a functional component because it doesn’t need to manage its state nor have access to the lifecycle methods. The data it needs is passed as props from the SelectOptions
component.
Improving functional components performance with React.memo
On functional components, we use React.memo to boost the performance of the FlatList by memoizing the result, according to React.memo documentation:
If your function component renders the same result given the same props, you can wrap it in a call to
React.memo
for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.
We need to create a function that compares the new and previous props passed to OptionItem
, on this case, the function is calledareEqual
.
Then, on the export, instead of using export default OptionItem;
we use export default React.memo(OptionItem, areEqual);
This way, we’re checking if the option has changed its selected state: If the new state is the same as the previous, the option won’t be rerendered, but if the option, for example, has been checked, it will be rerendered.
Improving class components performance with shouldComponentUpdate
If you prefer to use class components, you can do this performance optimization by using shouldComponentUpdate, according to the documentation:
Use
shouldComponentUpdate()
to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.
The method shouldComponentUpdate
takes care of comparing the previous selected state with the new one.
Now, if adding a console.log
on the OptionItem
component, we can see that only the changing item is rendered :)