Diagnosing slow FlatList scroll and blank cells
practical FlatList tuning.
memoize renderItem and items, supply getItemLayout for fixed heights, tune windowSize, maxToRenderPerBatch, initialNumToRender, and removeClippedSubviews; profile first.
WHAT THIS TESTS Whether you can reason about virtualization performance and apply FlatList's tuning props methodically, instead of randomly changing numbers.
A GOOD ANSWER COVERS Blank cells mean the user scrolled past the rendered window before the renderer produced new rows. First make each row cheap: wrap the item component in React.memo, hoist or useCallback the renderItem function, and avoid creating new objects or arrow functions in props. If item heights are fixed or computable, supply getItemLayout so FlatList can position cells without measuring, which directly reduces blanks and enables reliable scrollToIndex. Then tune the windowing props: windowSize controls how many viewports are kept rendered, maxToRenderPerBatch and updateCellsBatchingPeriod govern how aggressively new cells are produced during scroll, and initialNumToRender sets the first paint. removeClippedSubviews can help on Android. Always profile with the performance monitor before and after, since the right values depend on row complexity and device.
COMMON WRONG ANSWERS Setting windowSize to a very large value to eliminate blanks, which mounts far more rows and causes memory pressure and fresh jank. Ignoring renderItem cost and only touching numeric props. Forgetting getItemLayout for known-height rows, leaving FlatList to measure on the fly. Changing many props at once without measuring, so you cannot tell what helped.
LIKELY FOLLOW-UPS What exactly does getItemLayout let FlatList skip? How do windowSize and maxToRenderPerBatch interact during fast flings? When would FlashList be a better answer than tuning FlatList?
ONE CONCRETE EXAMPLE A feed of fixed-height 120px cards shows blanks on fast scroll. You wrap the card in React.memo, pass a memoized renderItem, and add getItemLayout returning length 120 and the computed offset. Blanks shrink immediately because positioning no longer waits on measurement. You then raise maxToRenderPerBatch modestly and confirm with the JS frame-rate monitor that scrolling holds near 60fps without the heap ballooning, rather than just maximizing windowSize.
Read the original → reactnative.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.