ScrollView vs FlatList

ScrollView Performance and When to Use FlatList Instead

ScrollView renders every child at once, visible or not: ideal for a form, wasteful for a catalog. FlatList renders lazily, mounting a first window of rows, adding more as they approach the viewport and unmounting rows far off screen. This benchmark counts the rows each renders before first layout:

src/demos/ListBench.tsx: counting rendered rows (excerpt)TSX
const ROWS = Array.from({ length: 2000 }, (_, i) => `Reading note ${i + 1}`);
const MODE: 'scroll' | 'flat' = 'scroll';
const start = performance.now();
let rendered = 0;
function Row({ label }: { label: string }) {
  rendered += 1;
  return <Text style={{ padding: 12 }}>{label}</Text>;
}
const report = () => console.log(`${MODE}: ${rendered} rows rendered, first layout ` +
  `after ${Math.round(performance.now() - start)} ms`);
export default function ListBench() {
  return MODE === 'scroll' ? (
    <ScrollView onLayout={report}>{ROWS.map((r) => <Row key={r} label={r} />)}</ScrollView>
  ) : (
    <FlatList data={ROWS} onLayout={report} renderItem={({ item }) => <Row label={item} />} />
  );
}

Run once as printed and once with MODE set to 'flat', each from a cold start, it logged:

Output of 37
 LOG  scroll: 2000 rows rendered, first layout after 5918 ms
 LOG  flat: 10 rows rendered, first layout after 675 ms

ScrollView built all 2,000 rows before the screen could lay out, almost six seconds in this debug build; FlatList built ten, its default initialNumToRender, and was on screen in under 0.7 s. Lists covers FlatList, SectionList and Shopify 175 's FlashList 7,238 , which recycles row views. ScrollView's default removeClippedSubviews on Android detaches off-screen children from the native hierarchy, but their JavaScript and shadow-tree work still happens.