I have this category filter component in my react native application. For the first time this component is loaded it does not scroll to given index item (i.e 3). I checked and the function scrollToIndex
is calling. But after loading the screen when do component re-rendering it is working.
Why does it not scroll down at the first time screen loaded ?
import React, { useCallback, useRef } from 'react'
import { StyleSheet, TouchableOpacity, FlatList, View } from 'react-native'
import { Badge, Text } from 'native-base'
import { connect } from 'react-redux'
import * as categoryActions from '../../Redux/Actions/categoryActions'
import { useFocusEffect } from '@react-navigation/native'
const CategoryFilter = (props) => {
const flatlistRef = useRef()
const handleSetSelectedCategoryId = (categoryId) => {
props.setSelectedCategoryId(categoryId)
}
const getItemLayout = (data, index) => ({
length: 50,
offset: 50 * index,
index,
})
const scrollToIndex = () => {
console.log('scroll to index called !')
let index = 3
flatlistRef.current.scrollToIndex({ animated: true, index: index })
}
useFocusEffect(
useCallback(() => {
scrollToIndex()
}, [])
)
const renderItem = ({ item, index }) => {
return (
<TouchableOpacity
key={item._id}
onPress={() => {
handleSetSelectedCategoryId(item._id)
}}
>
<Badge
style={[
styles.center,
{ margin: 5, flexDirection: 'row' },
item._id == props.selectedCategoryId
? styles.active
: styles.inactive,
]}
>
<Text style={{ color: 'white' }}>{item.name}</Text>
</Badge>
</TouchableOpacity>
)
}
return (
<View>
<FlatList
data={props.categories}
renderItem={renderItem}
keyExtractor={(item) => item._id}
horizontal={true}
ref={flatlistRef}
getItemLayout={getItemLayout}
/>
</View>
)
}
....
I had a similar problem and these were my findings:
It seems there could be a race condition where scrollToIndex is occuring before flatlist has finished calculating the item sizes using getItemLayout. So it doesn't throw an out of range error and considers the scroll successful.
One solution is:
setTimeout(() => scrollToIndex(), 500);
However this is not a great solution as there is no guarantee the flatlist will be 'ready' to scroll within the arbitrarily given 500ms, which would mean our delayed call would still not work.
The recommended way:
Set initialScrollIndex
on FlatList with the index we want to scroll to.
The data array (passed to FlatList) will need to already have the index you're looking for otherwise you will get an out of range error.
You should also note (from the docs):
This disables the "scroll to top" optimization that keeps the first initialNumToRender items always rendered and immediately renders the items starting at this initial index.
More info here: https://reactnative.dev/docs/flatlist#initialscrollindex