React Native · Mobile UI at native speed

How do you make a long list perform well?

HardperformanceflatlistvirtualisationUpdated Oct 2026
Quiz this track

Short answer

Virtualise with FlatList or FlashList, provide stable keys, memoise row components, avoid inline handlers, and tune batch size, window size and item layout. Measure on a low-end device before and after.

List performance is usually a combination of render cost per row and the amount of layout work the list does. A FlatList only renders a window of items, but it still re-renders rows when props change and must estimate layout for items it has not measured.

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

type Row = { id: string; title: string };

const RowItem = memo(function RowItem({ title }: { title: string }) {
  return (
    <View style={{ padding: 12 }}>
      <Text>{title}</Text>
    </View>
  );
});

export function Feed({ rows }: { rows: Row[] }) {
  return (
    <FlatList
      data={rows}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <RowItem title={item.title} />}
      getItemLayout={(_, index) => ({ length: 56, offset: 56 * index, index })}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={7}
      removeClippedSubviews
    />
  );
}
Fixed-height rows allow getItemLayout, which removes expensive measurement work.

The main levers

  • Stable keys from server IDs, never array index for reorderable data
  • Memoised row components with primitive props
  • A single stable renderItem function, not a new closure per render
  • getItemLayout when rows have a known fixed height
  • Tuned windowSize, initialNumToRender and maxToRenderPerBatch
  • FlashList or a native list when the dataset is very large or highly dynamic

Images inside rows are a common hidden cost. Downscale assets to the rendered size, use a caching image component, and avoid decoding full-resolution photos for thumbnails. Also avoid heavy work in renderItem, such as formatting dates or filtering arrays; precompute it once.

removeClippedSubviews can help on Android but has caused rendering glitches in some versions. Verify it on real devices rather than enabling it blindly.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1When would you use FlashList instead of FlatList?
  2. 2Why is an inline renderItem closure a problem?
  3. 3What does getItemLayout actually save?
  4. 4How do you profile a janky list?

Say it in the interview

I start by making each row cheap: stable keys, a memoised row component, primitive props and no heavy formatting in render. Then I tune the virtualisation window and add getItemLayout for fixed-height rows, or move to FlashList when the list is very large. I verify with profiling on a low-end Android device, because list jank rarely shows up on a fast simulator.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live React Native mock interview and get scored feedback on depth, clarity and confidence.