Your React Native FlatList lags because AI wrote it. Here's the prompt that fixes it
Ask ChatGPT or Claude for "a list of products in React Native" and you'll get a FlatList that works. Scroll it with 500 items on a mid-range Android phone, though, and you'll see blank rows, jumpy scrolling and dropped f
Ask ChatGPT or Claude for "a list of products in React Native" and you'll get a FlatList that works. Scroll it with 500 items on a mid-range Android phone, though, and you'll see blank rows, jumpy scrolling and dropped frames.
The model isn't wrong. It just wasn't asked for speed. Here are the four fixes I ask for every time, and the prompt I paste with my component.
1. A stable keyExtractor, not the index
<FlatList
data={products}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
AI often leaves the key out, or falls back to the index. When items are inserted, removed or re-sorted, index keys make React re-render rows that didn't change, and row state can end up attached to the wrong item.
2. A memoized row and a stable renderItem
const ProductRow = React.memo(function ProductRow({ item }: { item: Product }) {
return (
<View style={styles.row}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.price}>{item.price}</Text>
</View>
);
});
const renderItem = useCallback(
({ item }: { item: Product }) => <ProductRow item={item} />,
[]
);
Without these, every parent re-render (a search box, a timer, a context update) re-renders every visible row. React.memo skips rows whose props didn't change, and useCallback stops renderItem from being a new function on every render.
3. getItemLayout when rows have a fixed height
const ROW_HEIGHT = 72;
<FlatList
getItemLayout={(_, index) => ({
length: ROW_HEIGHT,
offset: ROW_HEIGHT * index,
index,
})}
/>
If every row is the same height, tell the list. It can then skip measuring rows, and scrollToIndex jumps straight to the right place instead of guessing.
4. Render less up front
<FlatList
initialNumToRender={10}
windowSize={5}
removeClippedSubviews
/>
initialNumToRender controls the first paint. windowSize controls how many screens' worth of rows stay mounted around the viewport (the default, 21, is a lot). Smaller numbers mean less memory and work. Too small, and you'll see blank areas on fast scrolls, so test on a real device.
The prompt
Paste your component after this:
Refactor this FlatList for performance:
- stable keyExtractor from item.id
- React.memo row component + useCallback renderItem
- getItemLayout (row height 72)
- initialNumToRender 10, windowSize 5
Don't add libraries. Keep my naming. Explain each change in one line.
The last two lines matter as much as the fixes. "Don't add libraries" stops the model from swapping in a new list package you didn't ask for. "Explain each change" lets you catch a wrong assumption, for example rows that aren't actually fixed height, before it ships.
Measure before and after
Turn on the Perf Monitor (shake the device β Perf Monitor) and watch the JS and UI frame rates while you fling the list. If the JS frame rate drops during scroll, the row components are doing too much work. If the UI frame rate drops, look at images and heavy styles in the rows.
I keep a set of prompts like this for every stage of a React Native app: planning screens, building features, debugging Metro and Gradle errors, keeping API keys out of the bundle, and shipping to Google Play.
- 10 of them are free as a PDF: 10 AI Prompts for React Native Devs
-
The full guide (118 pages, 50+ prompts): AI App Builder, 20% off with code
EARLYBFuntil Nov 15
Daily tips on X: @rn_aibuilder
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.