Flatlist onEndReached gets called multiple times when the height of the ListFooterComponent changes
Description
FlatList can enter a state where onEndReached gets called in a loop if I use the onEndReached prop to fetch the next page of the data and this causes a change in the height of ListFooterComponent (see attached screen recording).
Adding a fixed footer height in ListFooterComponentStyle to the component fixes the issue, however this isn't optimal as we would like to display different types of content depending on the state of the data.
Example code:
import {useCallback, useState} from 'react';
import {
FlatList,
StyleSheet,
Text,
View,
ActivityIndicator,
} from 'react-native';
const ListFooter = ({isLoading}: {isLoading: boolean}) => {
if (isLoading) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.endReachedContainer}>
<Text>End reached</Text>
</View>
);
};
const App = () => {
const [loading, setLoading] = useState(false);
const fetchData = async () => {
try {
setLoading(true);
await new Promise<void>(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
} finally {
setLoading(false);
}
};
const onEndReached = async () => {
console.log('CALLING ON END REACHED');
await fetchData();
};
const renderItem = useCallback(({item}: {item: number}) => {
return (
<View style={styles.listItemContainer}>
<Text>{item}</Text>
</View>
);
}, []);
return (
<FlatList
data={Array.from({length: 10}).map((_, index) => index)}
renderItem={renderItem}
onEndReached={onEndReached}
onEndReachedThreshold={1}
ListFooterComponent={<ListFooter isLoading={loading} />}
// Adding this prop fixes it:
// ListFooterComponentStyle={{height: 600}}
/>
);
};
const styles = StyleSheet.create({
listItemContainer: {
height: 300,
borderColor: 'black',
borderWidth: 1,
alignItems: 'center',
justifyContent: 'center',
},
loadingContainer: {
height: 200,
backgroundColor: 'pink',
alignItems: 'center',
justifyContent: 'center',
},
endReachedContainer: {
height: 600,
backgroundColor: 'orange',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
Steps to reproduce
- Clone the repo with reproducer code
- Run the app on either iOS or Android (bug seems to be worse on Android)
- Scroll to the bottom of the list - you should notice the footer changing multiple times between loading and finished state. You will also notice multiple logs being fired from the
onEndReachedfunction as it gets called again and again.
React Native Version
0.76.5
Affected Platforms
Runtime - Android, Runtime - iOS
Output of npx react-native info
System:
OS: macOS 14.4.1
CPU: (8) arm64 Apple M1 Pro
Memory: 291.98 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 20.14.0
path: ~/.nvm/versions/node/v20.14.0/bin/node
Yarn:
version: 1.22.22
path: ~/.nvm/versions/node/v20.14.0/bin/yarn
npm:
version: 10.7.0
path: ~/.nvm/versions/node/v20.14.0/bin/npm
Watchman:
version: 2024.10.21.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.15.2
path: /Users/kristine/.rvm/gems/ruby-2.7.6/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.5
- iOS 17.5
- macOS 14.5
- tvOS 17.5
- visionOS 1.2
- watchOS 10.5
Android SDK:
Android NDK: 26.2.11394342
IDEs:
Android Studio: 2024.2 AI-242.23339.11.2421.12550806
Xcode:
version: 15.4/15F31d
path: /usr/bin/xcodebuild
Languages:
Java:
version: 21.0.2
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 15.0.1
wanted: 15.0.1
react:
installed: 18.3.1
wanted: 18.3.1
react-native:
installed: 0.76.5
wanted: 0.76.5
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
-
Reproducer
https://github.com/KristineTrona/flatlist-onEndReached-called-in-loop
Screenshots and Videos
Bug:
https://github.com/user-attachments/assets/fb8054d1-210c-426c-972e-80b2c791455f
With fixed height:
https://github.com/user-attachments/assets/6ba35b71-c8d5-40e7-8092-2b7c2dfe5bda
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.
+1
+1