Four props decorate a list without touching its data. ListHeaderComponent scrolls in above the first row, ListFooterComponent below the last, ItemSeparatorComponent goes between rows (never before the first or after the last), and ListEmptyComponent replaces the rows when data is empty, while the header and footer still show. Each takes a component or an element:
const books = catalog(12);
const renderItem = ({ item }: { item: Book }) => <BookRow book={item} />;
const keyExtractor = (item: Book) => String(item.id);
export default function CatalogList() {
return (
<FlatList data={books} renderItem={renderItem} keyExtractor={keyExtractor}
ListHeaderComponent={<Text style={s.header}>BookNest · {books.length} books</Text>}
ListFooterComponent={<Text style={s.note}>End of the catalog</Text>}
ListEmptyComponent={<Text style={s.note}>No books yet.</Text>}
ItemSeparatorComponent={() => <View style={s.separator} />} />
);
}The left screen of the figure in Refresh and Infinite Scroll shows the result. The separator (s.separator, one pixel high) starts 80 dp in, past the cover, as system lists indent theirs. An inline element or separator function is a new object on every render; that is harmless here, but hoist them for a list whose parent renders often. Put controls that must stay visible, such as a search box, above the list in a plain View, not in the header.