Lesson 7 / 25

FlatList and SectionList

Render only what is on screen.

Virtualised lists

A ScrollView renders all its children at once, which is fine for short content but slow and memory-hungry for long lists. FlatList is virtualised: it renders items near the visible window and recycles the rest as you scroll. You pass data, a renderItem function and a keyExtractor that returns a stable unique string key. SectionList does the same for grouped data with section headers. Useful props include ListEmptyComponent, ItemSeparatorComponent, onEndReached for infinite scrolling, refreshing and onRefresh for pull-to-refresh, and performance knobs such as initialNumToRender, windowSize and getItemLayout for fixed-height rows. Community alternatives such as FlashList focus on even better recycling.

Scrolling, typing and tapping

Virtualised lists keep long feeds fast, while inputs, the keyboard and gestures need mobile-specific care.

Three ideas: FlatList and SectionList, forms and the keyboard, touch and gestures.
Figure 3.1 — Virtualised lists, inputs and gestures.

A list with pull-to-refresh and paging

FlatList with stable keys and a memoised row.

import { memo, useCallback } from "react";
import { FlatList, Text, View } from "react-native";

type Order = { id: string; title: string; total: number };

const OrderRow = memo(function OrderRow({ order }: { order: Order }) {
  return (
    <View style={{ height: 64, padding: 16 }}>
      <Text>{order.title} - {order.total.toFixed(2)}</Text>
    </View>
  );
});

export function OrderList({ orders, loadMore, refreshing, onRefresh }: {
  orders: Order[]; loadMore: () => void; refreshing: boolean; onRefresh: () => void;
}) {
  const renderItem = useCallback(({ item }: { item: Order }) => <OrderRow order={item} />, []);
  return (
    <FlatList
      data={orders}
      keyExtractor={(o) => o.id}
      renderItem={renderItem}
      getItemLayout={(_, index) => ({ length: 64, offset: 64 * index, index })}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
      refreshing={refreshing}
      onRefresh={onRefresh}
      ListEmptyComponent={<Text>No orders yet</Text>}
    />
  );
}

Never use the index as a key

Use a stable id from your data. Index keys break when items are inserted, removed or reordered and can show the wrong row state.

A train window

You only see the few metres of track outside the window, so there is no need to lay out the whole route at once. FlatList only builds the rows you can see.

Quick check: Why prefer FlatList over ScrollView for a 5,000-item feed?

  • FlatList virtualises, rendering only items near the visible area
  • ScrollView cannot scroll vertically
  • FlatList downloads data automatically
  • ScrollView only works on iOS
Answer

FlatList virtualises, rendering only items near the visible area — Virtualisation keeps memory and render time bounded.