Reputation: 251
I am trying to render a list of ~250 images in 3 columns using FlatList in RN0.43, and I change the width of the images in the onLayout function of the FlatList to fit the width of screen.
The initial performance is ok, but after some scrolling up/down, sometimes it takes a second or 2 until images are shown.
it is even worse if I change to screen orientation, it takes 2~3 seconds to get screen updated.
a few findings:
after screen rotation, it takes a second or 2 until FlatList.onLayout is called
after FlatList.onLayout and update of image width, each image (about half of the list, ~150 images; while only ~15 are shown) is rendered 2~4 times, while render() is only called once.
question:
Thanks.
tested on: GalaxySII (4.1.2) and Android SDK emulator (7.1.1)
var data = [
require('./res/img/Search.png'),
require('./res/img/test - Copy.png'),
// ~250 items
...];
class app extends React.Component {
renderItem (info, width) {
console.log('renderItem', info.index);
if(width !== this.width) {
this.imageStyle = {width: width-MarginHorizontal , height: width-MarginHorizontal, resizeMode: 'contain'};
}
return (
<Image
source = {info.item}
key = {info.index}
style={this.imageStyle}/>
);
}
render() {
console.log('Test.render');
return (
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#F5FCFF'
}}>
<GridList
numColumns={3}
columnWrapperStyle={{ alignItems: 'center', marginVertical: 5, justifyContent: 'space-around'}}
data={data}
renderItem={this.renderItem}
/>
</View>
);
}
}
class GridList extends Component {
onLayout(event) {
console.log('GridList.onLayout()');
let newColumnWidth = event.nativeEvent.layout.width/ this.numColumns;
this.layout = Object.assign({},event.nativeEvent.layout);
if( undefined === this.columnWidth || Math.abs(newColumnWidth - this.columnWidth) > WidthTolerance ) {
this.columnWidth = newColumnWidth;
if(this.isComponentMounted) {
this.setState({renderCount: this.state.renderCount+1});
} else {
this.state.renderCount +=1;
}
}
}
render() {
console.log('GridList.render()');
return (
<FlatList
{...(this.modifiedProps)}
renderItem={(info) => { return this.props.renderItem(info, this.columnWidth); }}>
{this.props.children}
</FlatList>
);
}
}
Upvotes: 19
Views: 11468
Reputation: 517
I strongly recommend everybody to read the article in the link attached below to optimize your flatlist. https://reactnative.dev/docs/optimizing-flatlist-configuration
Upvotes: 0
Reputation: 2446
Disclaimer: I know that the question is old, but here is my response anyways.
My app has a hand full of lists with 500+ items. So, we got to a point where the app was crashing on popular not-bad phones. Then I've made this extensive research about performance on FlatLists.
The FlatList
component was presented as a alternative for the old ScrollView
. The problem is that ScrollViews render all your list at once so they perform visually better, but there is a trade off in memory consumption, that leads to app crashes.
So Flat Lists are a necessary evil. They essentially only render items that are visible, which is a huge gain on memory consumption, but a pain for visual performance, specially for heavy/complex items, that happens to be your case with those responsive images.
There are a lot of strategies that you can implement to mitigate your problem.
Use cached and performatic images, such as react-native-fast-image. Every operation that you can remove or abbreviate for freeing the Javascript thread: do it (every image is a new Image()
, so, if they are cached, you have your loaded
hook called sooner)
Your list item component is a read-only component, which is supposed to be 'dumb'. Implement a shouldComponentUpdate() { return false }
or a more solid update control method as needed. This is HUGE perf boost.
Remove console.logs anywhere near your list. They slow the Javascript thread really bad.
Build your app for production and test it. It becomes almost always twice or three times faster. Dev env is slow because of debugging.
Give this article a good read for more strategies.
FlatList
IS a slow component. This is a known, open and well documented issue. Do what you can to improve it, and let's hope future releases may fix this.
Upvotes: 14
Reputation: 1597
You're re-creating lots of styling objects for each row of the list individually. This puts a lot of traffic on the JS->Native bridge. Try using stylesheet instead of passing the styles inline.
Upvotes: 0
Reputation: 181
Yes I was having the same problem - multiple images & videos in list in react native So I removed Flatlist instead of this I preferred to use ListView to render fast & to fix touchability issue on list item but Dont forget to set PureComponent to the list item
Upvotes: 0
Reputation: 1575
Try to set unique key for each item using keyExtractor
For Example:
render() {
return (
<List>
<FlatList
...
keyExtractor={item => item.email}
/>
</List>
);
}
Upvotes: -1