I'm having a trouble adding scroll/jump to certain index functionality on FlatList in react-native. My FlatList items are vary in size (height) which makes me unable to implement getItemLayout
since this requires me to have prior knowledge about the FlatList item size, therefore I cannot use scrollToIndex
(which requires getItemLayout
to be implemented).
My solution was to get each item's size when rendered by using onLayout
and map them with their index. I can then use each item size to get their offset and use scrollToOffset
to jump to the given item (by using scrollToItem
function in the code below). The issue here is that I am not able to jump to certain item until that item has been rendered.
My temporary solution for that is by tweaking initialNumberToRender
close to the number of data and set the windowSize
props as high as possible so that all of the items will be rendered (even though the user doesn't scroll down).
getOffsetByIndex = (index) => {
let offset = 0;
for (let i = 0; i < index; i++) {
const elementLayout = this.layoutMap[index];
if (elementLayout && elementLayout.height) {
offset += this.layoutMap[i].height;
}
}
return offset;
};
scrollToItem = (index) => {
const offset = this.getOffsetByIndex(index);
this.flatListRef.scrollToOffset(offset);
};
addToLayoutMap = (layout, index) => {
this.layoutMap[index] = layout;
};
render(){
return(
<FlatList
ref={this.flatListRef}
data={this.state.data}
renderItem={() => <View onLayout={this.addToLayoutMap}> <SomeComponent/> </View>}
initialNumToRender={this.state.data.length / 5}
windowSize={this.state.data.length}
/>
);
}
This solution works with small number of data, but when the data is large (containing ~300 of rows), it will take long time to be rendered get all the item size, preventing the user to jump to the last item directly for example.
Is there any efficient way to do it? Also, rendering all the rows is so memory consumptive and negates the benefit of using FlatList.
If you are using a FlatList in React Native, there's a chance you will want to use the scrollToIndex function to scroll to a certain item's index. Unfortunately, this function is a lot easier to use with fixed item heights where it is easy to implement the required getItemLayout function.
In Flatlist set scrollsToTop={false} this will retain position when you navigate back from detail screen.
As opposed to the ScrollView, the FlatList renders only those elements that are currently being displayed on the screen (default: 10 items). Thus, it does not have any impact on the performance of the application. So, it is preferable to use the FlatList Component to display a large list of data.
You can dynamically split your data according to scroll direction. If scroll goes up prepend data to your state and same for opposite direction. Then use onScrollToIndexFailed
like this :
<FlatList
ref={this.flatListRef}
data={this.state.data}
renderItem={() => <View> <SomeComponent /> </View>}
initialNumToRender={this.state.data.length / 5}
onEndReached={(e) => {
// Append data
}}
onScroll={(e) => {
if (e.nativeEvent.contentOffset.y == 0) {
// Prepend data
}
}}
onScrollToIndexFailed={(error) => {
this.flatListRef.scrollToOffset({ offset: error.averageItemLength * error.index, animated: true });
setTimeout(() => {
if (this.state.data.length !== 0 && this.flatListRef !== null) {
this.flatListRef.scrollToIndex({ index: error.index, animated: true });
}
}, 100);
}}
/>
You can workaround this issue. This worked for me and took me a lot of time to get that work :))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With