I'm creating a FlatList with 20,000 records and a question came up.
What is the recommended limit to be loaded at once into a FlatList?
And after that is it recommended to use an Infinite Scroll?
Loading like 20 items at once and then infinite load is a good way. But you need to optimize your flatlist (remove clipped subviews, set item layout manually, handle batchs, ...)
More infos https://reactnative.dev/docs/optimizing-flatlist-configuration
Example
<FlatList
ref={(ref) => {this.searchListRef = ref}}
data={this.state.search_list}
renderItem={this.renderSearchItem}
keyExtractor={(item, index) => index}
onEndReached={(infos) => this.searchMore(infos)}
onEndReachedThreshold={0.8}
numColumns={2}
removeClippedSubviews
initialNumToRender={6}
updateCellsBatchingPeriod={100}
maxToRenderPerBatch={6}
windowSize={10}
onScroll={(e) => this.handleSearchScroll(e.nativeEvent.contentOffset.y)}
getItemLayout={(data, index) => (
{length: 316, offset: 316 * index, index}
)}
ListEmptyComponent={<View>...</View>}
ItemSeparatorComponent={() => <View style={{marginBottom: 10}}></View>}
ListFooterComponent={<View>...</View>}
ListHeaderComponent={<View>...</View>}
/>
Related
I'm using flatlist to show a feed of posts (like tiktok), the issue is that sometimes is showing up a part of the second post instead of scroll down to it. See the picture below:
That issue happens when I'm scrolling down faster.
Flatlist code:
<FlatList
showsVerticalScrollIndicator={false}
data={videos}
keyExtractor={(item, index) => index.toString()}
onEndReachedThreshold={3}
onEndReached={() => {
if (!isFetching) {
debouncedFetchMore();
}
}}
snapToInterval={PICTURE_HEIGHT}
disableIntervalMomentum
viewabilityConfig={viewabilityConfig}
onViewableItemsChanged={onViewableItemsChanged}
onRefresh={() => getPosts('video', FetchMode.REFRESH)}
refreshing={false}
//Optimization
renderItem={renderItem}
removeClippedSubviews
initialNumToRender={1}
maxToRenderPerBatch={2}
windowSize={2}
// Scrolling fixes
decelerationRate="fast"
snapToAlignment="start"
overScrollMode="never"
bounces
scrollEventThrottle={8}
getItemLayout={(_, index) => ({
length: PICTURE_HEIGHT,
offset: PICTURE_HEIGHT * index,
index,
})}
pagingEnabled
ref={refFlatList}
/>
I have a Horizontal FlatList and in RTL view the FlatList just constantly call onEndReached method but that's not the case in LTR view.
It's a big issue that's not solved https://github.com/facebook/react-native/issues/19979
Did anyone try to find a workaround for this issue ?
Here is my implementation:
<FlatList
horizontal
directionalLockEnabled
data={recommendedPosts}
onRefresh={handleRefresh}
refreshing={isRefreshing}
onEndReachedThreshold={0.5}
onEndReached={onEndReached}
keyExtractor={(item) => item?._id}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
ListHeaderComponentStyle={styles.footerStyle}
ListFooterComponentStyle={styles.footerStyle}
renderItem={({ item, index }) => (
<AdGridCard
ad={item}
containerStyle={styles.recommendedCard}
onPress={() => goToDetails(item?._id, index)}
/>
)}
contentContainerStyle={styles.contentContainerStyle}
getItemLayout={(d, index) => {
return { length: hp(250), offset: index * hp(250), index };
}}
ListFooterComponent={<LoadingComponent isLoading={loading} />}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
I am facing weird issue when rendering SectionList. When adding a new item to the list, previously added item duplicated. Not happening on vary first render and first item add, only happening when add new item on a second time and then going forward
Here is the code :
<SectionList
ref={ref => this.sectionList = ref}
sections={this.state.itemData}
renderItem={({ item }) => this.renderMessages(item)}
renderSectionFooter={({ section }) => this.renderSectionHeader(section)}
inverted
onEndReachedThreshold={0.1}
onEndReached={() => this.handleMoreData()}
showsVerticalScrollIndicator={false}
style={{ flex: 1, margin: 5, opacity: 1 }}
removeClippedSubviews={false}
/>
I checked my array that i am passing, No duplicate data in it & also renderItem logs looks fine
You are missing a keyExtractor.
Try something like:
keyExtractor={(item, index) => item + index}
If your this.state.itemData elements have a unique identifier you could use that as a keyExtractor:
keyExtractor={(item) => item.id}
Also when adding new items to your list you might want to consider using extraData to make sure the sectionList will re-render
extraData={this.state}
I have flatlist with enabled horizontal option like page, it work well when is portrait or landscape load. When mode are changed width and height are mess up. I try to calculate width and height in addEventListener. Is there some better solution. Can re render flatlist without losing state and props. This is getItemLayoutPot where define layout.
getItemLayout = (data, index) => (
{length: this.state.width, offset: this.state.width * index, index}
)
<FlatList
onViewableItemsChanged={this.onViewableItemsChanged }
viewabilityConfig={{
itemVisiblePercentThreshold: 50
}}
ref={ref => this.flatListRef = ref }
data={dataar}
horizontal={true}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
showsHorizontalScrollIndicator={false}
removeClippedSubviews={false}
initialNumToRender={20}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
initialScrollIndex={this.state.numPage}
getItemLayout={this.getItemLayout}
pagingEnabled={true} ....
I have inverted vertical FlatList in my chat app, which shows newest message in bottom and oldest message in top (likes all other chat applications)
The problem is when I want to add new messages to bottom of my list, FlatList automatically jump to bottom-end of the list!
All I need is to prevent scrolling in this situation
Here is my FlatList:
<FlatList
inverted
style={{flex: 1}}
data={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem}
/>
And here is the code to add newest messages to list
const data = [ ...newMessages, ...this.state.data ];
this.setState({ data });
Your case look simple but you are adding new message at top then reverse it to bottom last position using inverted flag
Could remove inverted flag and add new item at last simply const data = [...this.state.data, ...newMessages];
<FlatList
style={{flex: 1}}
data={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem}
/>
const data = [...this.state.data, ...newMessages];
this.setState({ data });
I hope this will work
Put this in the view
<FlatList
data={this.state.data}
ref={ref => {
this.flatListRef = ref;
}}
initialScrollIndex={0}
keyExtractor={item => item.id}
extraData={this.state.refresh}
renderItem={({item, index}) => {
// animation={animation}
return (
<ListItem
inAnimation={inAnimation}
outAnimation={outAnimation}
duration={duration}
easing={easing}
isDeleted={item._isDeleted}
id={item.id}
item={item}
/>
);
}}
`/>`
Run this in a function
this.flatListRef.scrollToIndex({
animated: true,
index: nextProps.indexScroll})
});
You should use a workaround to achieve this. If you check the documentation for FlatList (which extends the props of ScrollView), you'll see that all you need to do is set the scrollEnabled prop to false to disable scrolling. How and where you choose to do this will be up to you since you didn't really post a lot of code. A simple way to handle this would be to use state:
<FlatList
...
scrollEnabled={this.state.scrollEnabled}
/>
In your case you could change the state when the new data is being loaded and change it back when it is rendered.
There is an open issue on Github about this case.