Skip to main content

Essential Performance Props

drawDistance
number
Draw distance for advanced rendering (in dp/px). This controls how much content is rendered outside the visible viewport.Higher values mean more items are pre-rendered, reducing blank space during fast scrolling but using more memory.
<FlashList
  data={items}
  renderItem={renderItem}
  drawDistance={500} // Render 500dp worth of items beyond viewport
/>
Only adjust this if you’re experiencing blank space during fast scrolling. The default value works well for most use cases.

Item Layout Optimization

overrideItemLayout
(layout: { span?: number }, item: TItem, index: number, maxColumns: number, extraData?: any) => void
This method can be used to change column span of an item. Changing item span is useful when you have grid layouts (numColumns > 1) and you want few items to be bigger than the rest.Modify the given layout object. Do not return a value. FlashList will fallback to default values if this is ignored.
Performance: This method is called very frequently. Keep it fast.
<FlashList
  data={items}
  renderItem={renderItem}
  numColumns={3}
  overrideItemLayout={(layout, item, index, maxColumns) => {
    // Make every 5th item span full width
    if (index % 5 === 0) {
      layout.span = maxColumns;
    }
  }}
/>
Parameters:
  • layout: Object with span property to modify
  • item: The data item
  • index: Index in the data array
  • maxColumns: Total number of columns (value of numColumns prop)
  • extraData: Value from extraData prop
Example - Pinterest-style Grid:
const items = [
  { id: '1', type: 'featured' },
  { id: '2', type: 'normal' },
  { id: '3', type: 'normal' },
  { id: '4', type: 'featured' },
];

<FlashList
  data={items}
  renderItem={({ item }) => (
    <GridItem item={item} isFeatured={item.type === 'featured'} />
  )}
  numColumns={2}
  overrideItemLayout={(layout, item) => {
    if (item.type === 'featured') {
      layout.span = 2; // Featured items span both columns
    }
  }}
/>

Recycling Configuration

maxItemsInRecyclePool
number
Maximum number of items in the recycle pool. These are the items that are cached in the recycle pool when they are scrolled off the screen.Unless you have a huge number of item types, you shouldn’t need to set this. Setting this to 0 will disable the recycle pool and items will unmount once they are scrolled off the screen.There’s no limit by default.
<FlashList
  data={items}
  renderItem={renderItem}
  maxItemsInRecyclePool={10}
/>
When to adjust:
  • Set to 0 if items have expensive cleanup (e.g., timers, subscriptions)
  • Increase if you have many item types and notice unmount/remount overhead
  • Keep default for most use cases

Render Optimization

getItemType
(item: TItem, index: number, extraData?: any) => string | number | undefined
Allows developers to override type of items. This will improve recycling if you have different types of items in the list. The right type will be used for the right item. Default type is 0.If you don’t want to change type for certain indexes, just return undefined.
Performance: This method is called very frequently. Keep it fast.
type FeedItem = 
  | { type: 'header'; title: string }
  | { type: 'post'; content: string; image?: string }
  | { type: 'ad'; adId: string };

<FlashList
  data={feedItems}
  renderItem={({ item }) => {
    switch (item.type) {
      case 'header': return <HeaderItem {...item} />;
      case 'post': return <PostItem {...item} />;
      case 'ad': return <AdItem {...item} />;
    }
  }}
  getItemType={(item) => item.type}
/>
Benefits:
  • Better recycling: Headers recycle headers, posts recycle posts, etc.
  • Prevents layout thrashing when item types have different sizes
  • More efficient memory usage
Performance Tips:
  • Return a simple string or number
  • Avoid complex calculations
  • Don’t create new objects/arrays
  • Use a property from the item if possible
removeClippedSubviews
boolean
When true, offscreen child views are removed from the native view hierarchy. This can improve scrolling performance on long lists. Inherited from ScrollView.
This is generally not needed with FlashList as it already handles view recycling efficiently.
<FlashList
  data={items}
  renderItem={renderItem}
  removeClippedSubviews={true}
/>

Performance Monitoring

onLoad
(info: { elapsedTimeInMs: number }) => void
This event is raised once the list has drawn items on the screen. It reports elapsedTimeInMs which is the time it took to draw the items.This is required because FlashList doesn’t render items in the first cycle. Items are drawn after it measures itself at the end of first render.
<FlashList
  data={items}
  renderItem={renderItem}
  onLoad={({ elapsedTimeInMs }) => {
    console.log(`List loaded in ${elapsedTimeInMs}ms`);
    analytics.track('list_load_time', { duration: elapsedTimeInMs });
  }}
/>
If you’re using ListEmptyComponent, this event is raised as soon as ListEmptyComponent is rendered.

Advanced Configuration

overrideProps
OverrideProps
Allows overriding internal ScrollView props. Props provided here are spread onto the internal ScrollView after all other props, so they take highest priority.
Use with caution — overriding internal props may interfere with FlashList’s layout and recycling behavior.
<FlashList
  data={items}
  renderItem={renderItem}
  overrideProps={{
    initialDrawBatchSize: 10,
    showsVerticalScrollIndicator: false,
  }}
/>
OverrideProps Type:
interface OverrideProps {
  initialDrawBatchSize?: number;
  [key: string]: any;
}

Performance Best Practices

1. Use getItemType for Mixed Content

// Good: Define item types
getItemType={(item) => item.type}

// Bad: Not using getItemType when you have different layouts

2. Optimize renderItem

// Good: Memoized component
const MemoizedItem = memo(({ item }) => <Item {...item} />);
renderItem={({ item }) => <MemoizedItem item={item} />}

// Bad: Creating new components every render
renderItem={({ item }) => <View><Text>{item.title}</Text></View>}

3. Use extraData Properly

// Good: Pass only what's needed
extraData={selectedId}

// Bad: Passing entire state object
extraData={state}

4. Key Extraction

// Good: Stable, unique keys
keyExtractor={(item) => item.id}

// Bad: Using index
keyExtractor={(item, index) => String(index)}

5. Avoid Expensive Operations in Render Callbacks

// Good: Fast, simple logic
getItemType={(item) => item.type}

// Bad: Complex calculations
getItemType={(item) => {
  const processed = complexCalculation(item);
  return processed.type;
})

Debugging Performance Issues

Blank Space During Scrolling

Cause: drawDistance is too low. Solution:
<FlashList
  drawDistance={500} // Increase if needed
/>

Scroll Lag

Cause: Heavy renderItem or too many item types without getItemType. Solution:
// Memoize components
const Item = memo(({ item }) => <ExpensiveComponent {...item} />);

// Define item types
getItemType={(item) => item.type}

Memory Issues

Cause: Too many items in recycle pool or memory leaks in items. Solution:
<FlashList
  maxItemsInRecyclePool={10} // Limit pool size
  // Or disable recycling if items have expensive cleanup
  maxItemsInRecyclePool={0}
/>

Build docs developers (and LLMs) love