Maximizing List Performance in React Native with FlatList
Learn how to replace ScrollView with FlatList, tune keyExtractor, getItemLayout, and initialNumToRender, and measure real‑world gains in frame rate and memory usage.
27 Jun 2026, 18:21 UTC

Concrete Problem: Laggy Long Lists
When a React Native app shows thousands of messages, images, or products, scrolling often stalls. Developers usually wrap the data in a ScrollView and let the framework render every child at once. The result is high memory consumption and frame drops, especially on mid‑range devices.
Thesis: FlatList is the Right Tool for the Job
React Native’s FlatList was built to solve exactly this. It lazily renders only the items that appear on screen, recycles views, and exposes hooks that let you pre‑compute layout and control how many items appear initially. Mastering these knobs can reduce frame drops from 30 FPS to 60 FPS and cut memory usage by half.
Key Techniques with Code
Below is a minimal, reproducible example that demonstrates the most common performance optimizations. Assume you have a fresh project created with npx react-native init Demo and you’re working on App.js.
import React from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
// 10,000 mock messages
const DATA = Array.from({ length: 10000 }, (_, i) => ({
id: i.toString(),
text: `Message #${i + 1}`,
}));
const Item = ({ text }) => (
{text}
);
export default function App() {
return (
item.id}
renderItem={({ item }) => }
// 1. Render only the visible items + a small buffer
initialNumToRender={20}
// 2. Tell FlatList the height of each item – 70px
getItemLayout={(data, index) => ({
length: 70,
offset: 70 * index,
index,
})}
// 3. Avoid triggering onEndReached too early
onEndReachedThreshold={0.5}
// 4. Prevent re‑renders caused by changing parent props
removeClippedSubviews
/>
);
}
const styles = StyleSheet.create({
item: { height: 70, justifyContent: 'center', paddingLeft: 15, borderBottomWidth: 1, borderColor: '#eee' },
});
**What each prop does:**
keyExtractorguarantees stable keys so React can reuse components.initialNumToRenderseeds the first render with a small set of items, reducing startup jank.getItemLayoutallows FlatList to compute scroll positions instantly; only works when each item has a fixed height.onEndReachedThresholdcontrols when the list considers the user near the end; a larger value can cause premature data loads.removeClippedSubviewsunmounts items that scroll off screen, freeing memory on Android.
Measuring the Gain
Run the app on a real device or emulator, open the built‑in Performance Monitor (Cmd+M or Ctrl+M → Show Perf Monitor). Observe the FPS bar while scrolling quickly. In a typical mid‑range phone, the monitor should stay above 60 FPS after the above tweaks.
For memory checks, launch Xcode Instruments (iOS) or Android Studio Profiler. Look at the “Memory Usage” chart; a FlatList should keep the process memory near the baseline, whereas a ScrollView with 10,000 children can spike above 200 MB.
Trade‑Offs and Limitations
- Dynamic item height:
getItemLayoutonly works with fixed heights. If items vary, you must omit it or useSectionListwithrenderItemthat calculates height on the fly. - Sticky headers & animations: FlatList’s default sticky header support is limited. Complex animations on scroll may require the
react-native-reanimatedlibrary. - Older iOS quirks: iOS 12 and below can flicker when
removeClippedSubviewsis enabled. Test on target OS versions. - onEndReached early trigger: A too‑low
onEndReachedThresholdcan fire before the user scrolls near the end, causing unnecessary network requests. Adjust based on expected scroll speed.
Actionable Checklist for Your Project
- Replace any
ScrollViewthat renders >200 items withFlatList. - Set
keyExtractorto a unique, stable value (e.g.,item.id). - If items have the same height, implement
getItemLayout. - Start with
initialNumToRender={20}and tweak based on perceived startup lag. - Profile on a real device: monitor FPS and memory, and adjust
onEndReachedThresholdas needed. - For lists that need dynamic heights or sticky headers, consider
SectionListorreact-native-reanimatedas a fallback.
By following these steps, you can transform a sluggish, memory‑heavy list into a smooth, responsive component that scales to thousands of items without sacrificing user experience.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.