-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FlatList performance: Scrolling is buggy and not smooth when virtualization is enabled #1337
Comments
You can close this but I'd appreciate some insights. |
I also noticed slow FlatList but I don't need dynamic heights so I was able to get good performance. Things to try:
I suspect getItemLayout will fix it for you. Before worrying about how to calculate the height, just set it to something fixed to test if that does solve the performance for you. If yes, then you can work out how to calculate. I believe FlatList is taken straight from RN so I assume native Views + Yoga perform better than divs + flexbox in browser. Probably not much can be done without rewriting FlatList which I assume is out of scope as RNW tries to stay close to RN. A third party like Twitter could open source theirs (if they have one) but you'd have to ask them |
Thanks but I use that already.
Just tried, unfortunately didn't help. Used |
I've just edited the first comment with a gif comparison, check it out. |
@brunolemos I have experienced this when a The example provided by RNW wraps FlatList with Also worth noting that while |
Scrolling is junky necolas/react-native-web#1337
I think the answer is use
It certainly seems to fix my code, for both FlatList and SegmentedList. A simpler example: class FilterItem extends React.PureComponent {
render() {
const { item, index } = this.props
return <Text key={index}>{item}</Text>
}
}
class FilterSeparator extends React.PureComponent {
render() {
return <View />
}
}
export default class SearchFilters extends React.Component {
render() {
return (
<FlatList
renderItem={({ item, i }) => <FilterItem item={item} index={i} />}
ItemSeparatorComponent={FilterSeparator}
/>
)
}
} |
I think it's some kind of bug, I already do all these common optimizations. Also there is no ScrollView above it. It works perfectly on ios and android, problem is only on browser. Here's the source code: https://github.com/devhubapp/devhub/blob/f08c991f9d9ca324c23ebbf92e7a6a1de8428e22/packages/components/src/components/cards/NotificationCards.tsx#L330 |
I am not entirely certain, but I think it might have something to do with FlatList and VirtualizedList seem to be taken directly from react-native, and do not contain any of the DOM specific customizations like we see in ScrollView, TextInput, and View. The vendor exports do, however, reference the DOM specific I think the FlatList performance suggestions in this thread are good, and definitely applicable since React is still managing the tree reconciliation, but may be outweighed by the need for a DOM specific optimization. I am not entirely sure what that optimization is, but I think @brunolemos is on to something with As an aside, the |
@brunolemos have you given this a look? https://github.com/Flipkart/recyclerlistview |
@brunolemos @pcooney10 |
I noticed on iPhone 6s and Samsung Galaxy S8 (using Android 8) scrolling with flatlist is very smooth, but I tried two phones using Android 9 (Samsung Galaxy S10, Essential Phone) and scrolling was very choppy. I switched over to RecycleListView and now all phones scroll very smooth without jank. |
@jsp3536 you talking about the web version running on the browser of these devices, right? I may try
|
Yes. I am happy with the performance of RecycleListView but I need to checkout react-window |
@brunolemos have you try with bounces false scrollEventThrottle 300 maxRenderToBatch 1 and updateCellsBatchingPeriod 100 and removeClippedSuvViews true (i dont know if this is implemented in web) |
What I found is that every time there are extra items loaded the flatlist will re render the whole list. Even if you use purecomponent. I now use a normal scrollview on the web and the performance is much, much better! |
do you use keys? |
and keys extractor? |
@francescoagati Yes, you should try to make a flatlist and log the render function of the item with the index you will see that it will log every time extra items are added, instead of only the newly rendered ones |
FlatList wasn't built to support the web, where the solution would probably have to involve juggling a bunch of web APIs to try to find extra performance from somewhere. I don't think supporting the web is a priority at the moment (cc @sahrens), but FB might eventually have a cross-platform solution and Google is working on a built-in virtualizer that might be something we can use one day. |
I am not sure the problem is with FlatList. I replaced it with Maybe there's something wrong with my app, maybe it's something on react-native-web internals, maybe it's react-window, maybe it's chrome, maybe it's the cost of the garbage collector. Needs more investigation, help much appreciated: devhubapp/devhub#155 |
Closing since I don’t have these issues anymore and they might have been mostly because the renders were a bit expensive. I’ve rewritten my list item components to be simpler. For example, their height are now pre-calculated (this is important) and they don’t do any computation inside the render. Also removed the deep nested custom components, it’s now a single ItemComponent as flat as possible. Things are fast now. I did switch to react-window on web, it is faster than FlatList but not a huge deal. The bigger optimizations were the other things I mentioned. |
@brunolemos Any documentation related to disableVirtualisation for web, android and iOS |
Just use a normal scrollview instead of a flatlist in the web @nihp. |
@RichardLindhout I am using iOS, here I need to know about the disableVirtualisation. I am using SrcollView and Flatlist in my app. Need to smoothen the scroll in iOS so I asked about disableVirtualisation |
There is no virtualization in the flatlist of react-native-web. |
I'm wrong I think, it is available in the DevHub source: https://github.com/devhubapp/devhub/blob/f08c991f9d9ca324c23ebbf92e7a6a1de8428e22/packages/components/src/components/cards/NotificationCards.tsx#L339 |
I solved this in my app by remaking my For context, I was displaying an infinite scroll search list of artists (think Netflix search.) I wanted to show users if they've liked the artist before or not, etc. I was originally looping through a list, passing each list item down to my component, and then grabbing metadata about my list item from within each component. Why not? After all, each component could just access the global state, right? Turns out, this was very expensive. I changed this by turning each card into a fully "dumb" component, with very little code. It only receives primitive props ( Oddly, adding I highly recommend making your list item nimble. Don't pass the entire list object down to it – only the data it needs. Keep any functions at the top level of the list component, and memoize them before passing them down to each item. And, as people have mentioned here, memoize each list item if they re-render too often and you're seeing issues. In case it's useful, these are the props I ended up with. I memoized every function I passed to <FlatList
data={hits}
removeClippedSubviews={Platform.OS !== 'web'}
renderItem={renderItemFast}
ListEmptyComponent={ListEmptyComponent} // memoized function
numColumns={itemsPerRow}
// force re-render when items per row changes, since this can't be changed on the fly
key={`list-${itemsPerRow}`}
initialNumToRender={10}
keyExtractor={keyExtractor}
onEndReached={fetchMore}
keyboardDismissMode="on-drag"
keyboardShouldPersistTaps="handled"
style={style.container}
/> |
Only add |
This works like a charm. I'm curious to know where there's a deprecated label on it. I have tried to optimize my Flatlists in all ways but I would always get a warning Of Flatlist not optimized. This looks like the best option for now. Also for those curious, there's another package called recyclerlistview which offers native performance |
@louicoder @viniciushernandes @brunolemos any better solution than |
I'm creating a messaging feature to an app and was having issues with sorting then updating state with new messages (10 new ones at a time) as the user scrolls through old messages. I would face trouble with this as I got to 40-50 messages. @nandorojo solution is good advice, but did not work for me because each message component has to calculate whether to show the date above it based on the previous message, pseudo-code is like this:
(if current message was sent today AND previous message was not sent today, then show "Today" above current message and show yesterday above previous message) Instead of sorting THEN updating the whole messages state variable in my FlatList, I resolved this by concatenating the new messages as the user scrolls and making the following change in my data prop on :
Array.slice() does the following according to developer.mozilla.org:
Updating 150 element long state array is very costly to performance especially when sorting WHILE scrolling. That was my issue. Another solution along the lines of what @nandorojo said is that you could do logic on the backend so it's easy to just display information based on what the front end receives. Credit to this StackOverflow post and Mozilla's developer docs on this matter. |
increasing windowSize fixed it for me |
The problem
It have a vertical FlatList with not that many items (~150). When virtualization is enabled and I scroll, there are lot's of FPS loss, I can see the lag clearly. Every time I scroll a little bit and a new dom element is added by the virtualization it happens.
On iOS simulator it's fast and smooth. On chrome is the worse, firefox is less bad but still not good.
If I use
disableVirtualization
, then it becomes super smooth, but it has its consequences, e.g. switching between screens is much more expensive.I played with all the virtualization options, didn't help much.
Twitter is quite fast and also has dynamic height, does it use the same FlatList we use? If not, would love if they could open source it.
I've considered react-window but it doesn't seem to support dynamic height (just-in-time measurement) yet. bvaughn/react-window#6. Maybe react-virtualized could help.
The problem is that these external solutions don't support things like
scrollToItem
,onViewableItemsChanged
, etc :(GIF comparison
With virtualization enabled + getItemLayout forcing height:100
Slow and buggy
Without virtualization (
disableVirtualization
)Scrolling is fast and smooth (screen change / first render is slower; memory usage is higher)
The text was updated successfully, but these errors were encountered: