SectionList virtualizes grouped data. Instead of data it takes sections, an array of objects that each have a data array plus whatever else you need, usually a title. renderSectionHeader and renderSectionFooter draw the group boundaries, and a section may override renderItem, keyExtractor or ItemSeparatorComponent for its own rows. BookNest groups its catalog by genre:
export function byGenre(books: Book[]) {
const groups = new Map<string, Book[]>();
for (const b of books) groups.set(b.genre, [...(groups.get(b.genre) ?? []), b]);
return [...groups].map(([title, data]) => ({ title, data }))
.sort((a, b) => a.title.localeCompare(b.title));
}
// ...
<SectionList sections={sections} keyExtractor={(b) => String(b.id)}
renderItem={({ item }) => <BookRow book={item} />}
renderSectionHeader={({ section }) => <Header title={section.title} />}
renderSectionFooter={({ section }) => (
<Text style={g.footer}>{section.data.length} books in {section.title}</Text>
)}byGenre is plain TypeScript with no React Native 36,878 imports, so it can be unit-tested without an emulator (Testing React Native Apps). To jump to a group, scrollToLocation({ sectionIndex, itemIndex }) plays the part of scrollToIndex.