import React, { FC, useState } from 'react'; import { ActivityIndicator, FlatList, FlatListProps, ListRenderItem, StyleSheet, Text, View } from 'react-native'; interface ItemProps{ index: number; } const Item: FC<ItemProps> = props => { const { index } = props; return ( <View style={styles.item}> <Text>List item { index }</Text> </View> ); } const Divider: FC = () => { return ( <View style={styles.divider} /> ) } const arr = new Array(200).fill(null); const ITEM_HEIGHT = 50 + StyleSheet.hairlineWidth; export default function App() { const [end, setEnd] = useState(false); const renderItem: ListRenderItem<null> = ({ index }) => { return ( <Item index={index} /> ); } const getItemLayout: FlatListProps<null>['getItemLayout'] = (data, index) => { return { length: ITEM_HEIGHT, offset: (data?.length ?? 0) * ITEM_HEIGHT, index } } const onEndReached = () => end || setEnd(true); const Footer = () => { if (end) { return null; } return ( <View style={styles.spinner}> <ActivityIndicator size="small" color="#333" /> </View> ) } return ( <View style={styles.container}> <FlatList data={arr} renderItem={renderItem} keyExtractor={(item, index) => index.toString()} initialNumToRender={20} maxToRenderPerBatch={40} getItemLayout={getItemLayout} ListFooterComponent={Footer} ItemSeparatorComponent={Divider} onEndReached={onEndReached} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#ecf0f1', padding: 8, }, item: { height: 50, justifyContent: 'center' }, divider: { height: StyleSheet.hairlineWidth, backgroundColor: '#999' }, spinner: { paddingVertical: 10, justifyContent: 'center', alignItems: 'center' } });