I have a list of users, which I render within FlatList
. Initially, I render 10 users, then when I scroll to the bottom on the page, I render 10 more and so on. When I don't have any more users to load, I display a button at the bottom on the page saying "No more users".
Just for the sake of testing - I wanted to navigate to the 2nd user when pressing this button. I am calling the function, yet, when I press the button I am not navigated to the second - there are no changes at all.
Here is my code:
const UsersScreen = (props) => {
const flatListRef = useRef(null);
const limit = 10;
const [users, setUsers] = useState([]);
const [noMore, setNoMore] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
(async () => {
let initialUsers = await fetchInitialUsers();
setUsers(initialUsers);
setLoading(false);
})();
}, []);
const fetchNextBatch = async () => {
let moreUsers;
try {
moreUsers = await fetchMoreUsers();
if (moreUsers.length == 0) {
setNoMore(true);
} else {
setUsers([...users, ...moreUsers]);
}
} catch (error) {
console.log(error);
}
};
const isCloseToBottom = ({
layoutMeasurement,
contentOffset,
contentSize,
}) => {
const paddingToBottom = 30;
return (
layoutMeasurement.height contentOffset.y >=
contentSize.height - paddingToBottom
);
};
function onLayoutFunction() {
// here I see "function on layout was called: [Function scrollToIndex]" on the terminal
console.log(
"function on layout was called: ",
flatListRef.current.scrollToIndex
);
//scroll to random element, just to see if scrollToIndex works
flatListRef.current.scrollToIndex({
index: 5,
viewPosition: 0,
viewOffset: 30,
});
}
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator />
) : (
<ScrollView
onScroll={({ nativeEvent }) => {
if (isCloseToBottom(nativeEvent)) {
fetchNextBatch();
}
}}
scrollEventThrottle={400}
>
<FlatList
numColumns={1}
horizontal={false}
data={users}
onLayout={() => onLayoutFunction()}
//do I need this?
getItemLayout={(data, index) => {
return { length: 120, index, offset: 120 * index };
}}
keyExtractor={(item) => item.id}
ref={(ref) => (flatListRef.current = ref)}
renderItem={({ item }) => <User user={item} />}
/>
</ScrollView>
)}
{noMore ? (
<TouchableOpacity onPress={onLayoutFunction}>
<Text style={{ fontSize: 15 }}>No more users</Text>
</TouchableOpacity>
) : null}
</View>
);
};
I've read too many posts regarding this topic, and still I don't see what I am doing wrong? Why I can not navigate to the index I want?
My UsersScreen
component is within stack navigator if that makes any difference?
CodePudding user response:
I think the problem is that the FlatList is nested inside a ScrollView. I tried removing the ScrollView and the ScrollToIndex function works.
<View style={styles.container}>
{loading ? (
<ActivityIndicator />
) : (
<FlatList
onScroll={({ nativeEvent }) => {
if (isCloseToBottom(nativeEvent)) {
fetchNextBatch();
}
}}
scrollEventThrottle={400}
numColumns={1}
horizontal={false}
data={users}
onLayout={() => onLayoutFunction()}
//do I need this?
getItemLayout={(data, index) => {
return { length: 120, index, offset: 120 * index };
}}
keyExtractor={(item) => item.id}
ref={(ref) => (flatListRef.current = ref)}
renderItem={({ item }) => <User user={item} />}
/>
)}
{noMore ? (
<TouchableOpacity onPress={onLayoutFunction}>
<Text style={{ fontSize: 15 }}>No more users</Text>
</TouchableOpacity>
) : null}
</View>