React Native list rendering
In this article I will not tell you that you need to use as little content as possible to display or cache images. No! We will only talk about real list optimization and it doesn’t matter what we need to display, because if the client says I want – you can’t argue with him.
Let’s start with the simplest example. Let’s say we have an array.
1 |
const list = [{_id: 567456, label: “CodingChipmunks”}, …] |
What is the easiest way to render a small list? It is correct to use the .map method which returns a new array and we can display the entire list. Well, let’s look at one example:
1 2 3 4 5 6 7 8 9 10 11 |
render() { return ( <View> {list.map((item) => ( <View> <Text>{item.label}</Text> <View>))} </View> ) } |
Correct? No! Never do that!
- First, you always need to specify key for each item. And please do not use for this index element in the array. Below I will tell you why.
- Secondly, the code looks messy
- Third, do not use anonymous functions
Why not to do it like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
renderItem = (item) => ( <View key={item._id}> <Text>{item.label}</Text> <View> ) render() { return ( <View> {list.map((item) => this.renderItem(item)} </View>) } |
or like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const Item = (item) => ( <View > <Text>{item.label}</Text> <View> ) class List extends React.Component { … render() { return ( <View> {list.map((item) => <Item key={item._id} />} </View>) } } |
Is it much better now? Not really.
It remains to make the final touch. Namely, do not use an anonymous function for rendering inside .map. After all, when we call the render method, each time we create a new function for rendering each item and it does not matter whether the component is updated or not. Never. I repeat, never do that. I often stumble upon code written in this format or when an experienced developer takes on a project and it already says so. And you know what? They don’t correct things, they themselves continue to write with words.
For what to try if before it was also not so good.
And immediately the question “What? How? Why? Don’t you want to make a project that you are working on better? ” All we need is to slightly change the rendering.
Namely:
1 2 3 4 5 6 7 |
render() { return ( <View> {list.map(this.renderItem)} </View> ) } |
And the last step we can do it by use the so-called PureComponent to render each item.
1 |
class Item extends React.PureComponent { ... } |
That was all we needed!
What if I have a large and complicated list?
I think we figured out the simplest rendering of the list. Next, let’s see what to do with dozens of elements for rendering in it. And do we need it to display quickly and smoothly? The answer is FlatList. Flatlist and all? Of course not. Let’s figure out what we can do with it and what optimization methods to use.
Basic example:
1 2 3 4 5 6 7 8 9 10 11 12 |
const list = [loyaltyCard1, loyaltyCard2, … , loyaltyCard100]; … renderItem = ({ item: loyaltyCard, index }) => (...) keyExtractor = loyaltyCard => loyaltyCard._id render() { <FlatList keyExtractor={this.keyExtractor} data={list} renderItem={this.renderItem} /> } |
Now we can not specify a key in each element, but specify the keyExtractor parameter, this should be a function that returns a unique identifier for each element in the array.
The renderItem will no longer pass the element itself, but an object containing three parameters:
- item – the element of the array itself
- index – the index of the element in the array
- separator – what we don’t need yet
Is that all optimization?
Let’s move on
If we want to tell our list that we need to redraw the elements but do not want to change the original data array, then there is a separate extraData parameter for this. When you change it, the list will be updated.
If we know the exact height of each layout, we can use getItemLayout. If you know in advance the height of your element, you can specify it and then you can skip the measurement of dynamic content
From the official ReactNative website:
1 2 3 |
getItemLayout = {(data, index) => ( {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index} )} |
But what if I do not know the height of the element but it never changes? Then you can use the getLayout method and find out this.
1 2 3 4 5 6 7 8 |
onLayout = (event) => { const {x, y, width, height} = event.nativeEvent.layout; do something with layout } … renderItem = ({ item: loyaltyCard, index}) => ( <View onLayout={this.onLayout} /> ) |
The array is too large and the whole list is being rendered soooooo long, that causes the braking? InitialNumToRender and maxToRenderPerBatch will save you. With them we can download content in parts.
- initialNumToRender indicates how many elements should be rendered at first boot. Always specify the amount to fill the visible part of the screen from bottom to top and even with a margin
- maxToRenderPerBatch indicates how many items will be loaded in the following batches
If you use lazyLoad through onEndReached and onEndReachedThreshold, then specify the amount that comes in api from one request, otherwise you will encounter problems with duplicating of items in the list.
Now let’s move on to the rather dubious optimization methods
I want to warn that these methods can cause malfunctions and that you use them at your own risk.
But what if you remove elements that are not in the visible area of the screen?
removeClippedSubviews – if this parameter is set to true then elements that are out of visibility will be hidden.
Be very careful as such a case is possible that with fast scrolling you will come across an empty space into which content will be loaded later.
I recommend using it with getItemLayout.
I also want to say that you can configure how many out of range elements will be hidden.
That’s probably all. There are several more methods that are used to optimize lists in ReactNative, but I consider them rather doubtful and I will not talk about them in this article not to confuse you.
Related Posts
Leave a Reply Cancel reply
Service
Categories
- DEVELOPMENT (103)
- DEVOPS (53)
- FRAMEWORKS (26)
- IT (25)
- QA (14)
- SECURITY (13)
- SOFTWARE (13)
- UI/UX (6)
- Uncategorized (8)