Skip to main content
If you are familiar with FlatList, you already know how to use FlashList. You can try out FlashList by changing the component name.

Basic Example

import React from "react";
import { View, Text } from "react-native";
import { FlashList } from "@shopify/flash-list";

const DATA = [
  { title: "First Item" },
  { title: "Second Item" },
];

const MyList = () => {
  return (
    <FlashList
      data={DATA}
      renderItem={({ item }) => <Text>{item.title}</Text>}
    />
  );
};

Migration from FlatList

To avoid common pitfalls, follow these steps for migrating from FlatList:
  1. Change component name: Simply replace FlatList with FlashList
  2. Remove key props: Scan your renderItem hierarchy for explicit key prop definitions and remove them. If you’re doing a .map(), use the useMappingHelper hook
  3. Handle component state: Check your renderItem hierarchy for components that use useState and verify whether that state needs to be reset when a different item is passed (see Recycling)
  4. Specify item types: If your list has heterogeneous views, pass their types using getItemType to improve performance
  5. Test in release mode: Do not test performance with JS dev mode on. FlashList can appear slower in dev mode due to a smaller render buffer
  6. Memoize props: Memoizing props passed to FlashList is more important in v2 to prevent unnecessary re-renders
  7. Add keyExtractor: This is important to prevent glitches due to item layout changes when scrolling upwards
  8. Use new hooks: Learn about useLayoutState and useRecyclingState for simplified state management
  9. Nest FlashLists: When nesting horizontal FlashLists in vertical lists, we highly recommend the vertical list to be FlashList too for better optimization
Do not test performance with JS dev mode on. Make sure you’re in release mode. FlashList can appear slower in dev mode due to a smaller render buffer.

Core Props

renderItem

renderItem
function
required
Takes an item from data and renders it into the list.
renderItem: ({ item, index, target, extraData }) => React.ReactElement | null;
Provides the following parameters:
  • item (Object): The item from data being rendered
  • index (number): The index corresponding to this item in the data array
  • target (string): The render target for the item:
    • Cell - For your list item
    • Measurement - For size measurement (won’t be visible)
    • StickyHeader - For sticky headers (use this to change appearance)
  • extraData (Object): The same extraData prop passed to FlashList
Example:
const renderItem = ({ item, index, target }) => {
  if (target === "StickyHeader") {
    return <StickyHeaderStyle>{item.title}</StickyHeaderStyle>;
  }
  return <Text>{item.title}</Text>;
};

<FlashList
  data={[{ title: "Title Text", key: "item1" }]}
  renderItem={renderItem}
/>;

data

data
array
required
For simplicity, data is a plain array of items of a given type.
data: ItemT[];

getItemType

getItemType
function
Allows developers to specify item types for improved recycling when you have different types of items in the list.
getItemType?: (item: T, index: number, extraData?: any) => string | number | undefined;
The right type will be used for the right item. Default type is 0. If you don’t want to change type for certain items, just return undefined. Example:
enum MessageType {
  Text,
  Image,
}

interface Message {
  type: MessageType;
  content: string;
}

<FlashList
  data={messages}
  renderItem={({ item }) => {
    switch (item.type) {
      case MessageType.Text:
        return <TextMessage message={item} />;
      case MessageType.Image:
        return <ImageMessage message={item} />;
    }
  }}
  getItemType={(item) => item.type}
/>;
This method is called very frequently. Keep it fast.

keyExtractor

keyExtractor
function
Used to extract a unique key for a given item at the specified index.
keyExtractor?: (item: object, index: number) => string;
Key is used for optimizing performance. Defining keyExtractor is also necessary when doing layout animations to uniquely identify animated components.
<FlashList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ItemView item={item} />}
/>

horizontal

horizontal
boolean
default:"false"
If true, renders items next to each other horizontally instead of stacked vertically.

numColumns

numColumns
number
Multiple columns can only be rendered with horizontal={false} and will zig-zag like a flexWrap layout.
Items should all be the same height - masonry layouts require the masonry prop.

ListHeaderComponent

ListHeaderComponent
React.ComponentType | React.ReactElement
Rendered at the top of all the items. Can be a React Component or a React element.

ListFooterComponent

Rendered at the bottom of all the items. Can be a React Component or a React element.

ListEmptyComponent

ListEmptyComponent
React.ComponentType | React.ReactElement
Rendered when the list is empty. Can be a React Component or a React element.

ItemSeparatorComponent

ItemSeparatorComponent
React.ComponentType
Rendered in between each item, but not at the top or bottom. By default, leadingItem and trailingItem props are provided.

contentContainerStyle

contentContainerStyle
ContentStyle
You can use this to apply padding to the whole content itself.
type ContentStyle = Pick<
  ViewStyle,
  | "backgroundColor"
  | "paddingTop"
  | "paddingLeft"
  | "paddingRight"
  | "paddingBottom"
  | "padding"
  | "paddingVertical"
  | "paddingHorizontal"
>;

extraData

extraData
any
A marker property for telling the list to re-render (since it implements PureComponent).
If any of your renderItem, Header, Footer, etc. functions depend on anything outside of the data prop, stick it here and treat it immutably.

Scroll Events

onEndReached

onEndReached
() => void
Called once when the scroll position gets within onEndReachedThreshold of the rendered content.

onEndReachedThreshold

onEndReachedThreshold
number
default:"0.5"
How far from the end (in units of visible length of the list) the bottom edge must be to trigger onEndReached.
A value of 0.5 will trigger onEndReached when the end of the content is within half the visible length of the list.

onStartReached

onStartReached
() => void
Called once when the scroll position gets within onStartReachedThreshold of the start of the content.
Useful for loading older content in infinite scroll scenarios like chat applications.
<FlashList
  data={messageData}
  onStartReached={() => loadOlderMessages()}
  onStartReachedThreshold={0.1}
  renderItem={({ item }) => <MessageItem message={item} />}
/>

onStartReachedThreshold

onStartReachedThreshold
number
default:"0.2"
How far from the start (in units of visible length) the top edge must be to trigger onStartReached.

Lifecycle Callbacks

onLoad

onLoad
(info: { elapsedTimeInMs: number }) => void
Raised once the list has drawn items on the screen.
Reports elapsedTimeInMs which is the time it took to draw the items. FlashList doesn’t render items in the first cycle - items are drawn after it measures itself at the end of first render.
This event is not fired if ListEmptyComponent is rendered.

onCommitLayoutEffect

onCommitLayoutEffect
() => void
Called before layout is committed. Can be used to measure list and make changes before paint.
Doing setState inside this callback can lead to infinite loops. Make sure FlashList’s props are memoized.

onViewableItemsChanged

onViewableItemsChanged
function
Called when the viewability of rows changes, as defined by the viewabilityConfig prop.
interface ViewToken {
  index: number;
  isViewable: boolean;
  item: any;
  key: string;
  timestamp: number;
}

onViewableItemsChanged?: (info: {
  viewableItems: ViewToken[];
  changed: ViewToken[];
}) => void;
If you are tracking the time a view becomes (non-)visible, use the timestamp property. We make no guarantees that viewability callbacks will be invoked immediately.

viewabilityConfig

viewabilityConfig
ViewabilityConfig
Default configuration for determining whether items are viewable.
interface ViewabilityConfig {
  minimumViewTime?: number;
  viewAreaCoveragePercentThreshold?: number;
  itemVisiblePercentThreshold?: number;
  waitForInteraction?: boolean;
}
Properties:
  • minimumViewTime (number): Minimum time (in ms) that an item must be physically viewable before the callback fires. Default is 250
  • viewAreaCoveragePercentThreshold (number): Percent of viewport (0-100) that must be covered for a partially occluded item to count as viewable
  • itemVisiblePercentThreshold (number): Percent of the item that is visible (0-100)
  • waitForInteraction (boolean): Nothing is considered viewable until the user scrolls or recordInteraction is called
Example:
<FlashList
  viewabilityConfig={{
    waitForInteraction: true,
    itemVisiblePercentThreshold: 50,
    minimumViewTime: 1000,
  }}
  onViewableItemsChanged={({ viewableItems }) => {
    console.log("Viewable:", viewableItems);
  }}
  data={data}
  renderItem={renderItem}
/>

Advanced Props

maintainVisibleContentPosition

maintainVisibleContentPosition
object
Configuration for maintaining scroll position when content changes. Enabled by default.
maintainVisibleContentPosition?: {
  disabled?: boolean;
  autoscrollToTopThreshold?: number;
  autoscrollToBottomThreshold?: number;
  animateAutoScrollToBottom?: boolean;
  startRenderingFromBottom?: boolean;
};
Example for chat interface:
<FlashList
  data={chatMessages}
  maintainVisibleContentPosition={{
    autoscrollToBottomThreshold: 0.2,
    startRenderingFromBottom: true,
  }}
  renderItem={({ item }) => <ChatMessage message={item} />}
/>

overrideItemLayout

overrideItemLayout
function
This method can be used to change column span of an item in grid layouts.
overrideItemLayout?: (
  layout: { span?: number },
  item: T,
  index: number,
  maxColumns: number,
  extraData?: any
) => void;
Useful when you have grid layouts (numColumns > 1) and want a few items to be bigger than the rest.
<FlashList
  data={gridData}
  numColumns={2}
  overrideItemLayout={(layout, item) => {
    layout.span = item.span; // Set span based on item
  }}
  renderItem={({ item }) => <GridItem item={item} />}
/>
This method is called very frequently. Keep it fast.

CellRendererComponent

CellRendererComponent
React.ComponentType
Each cell is rendered using this element. The root component should always be a CellContainer (the default).
Ensure that the original props are passed to the returned CellContainer. Example with Reanimated:
import Animated from "react-native-reanimated";
import { CellContainer } from "@shopify/flash-list";

const AnimatedCellContainer = Animated.createAnimatedComponent(CellContainer);

<FlashList
  CellRendererComponent={(props) => (
    <AnimatedCellContainer {...props} style={[props.style, animatedStyle]} />
  )}
  data={data}
  renderItem={renderItem}
/>;

Hooks

useLayoutState

const [state, setState] = useLayoutState(initialState);
Similar to useState but communicates the change in state to FlashList. Useful if you want to resize a child component based on local state. Example:
import { useLayoutState } from "@shopify/flash-list";

const MyItem = ({ item }) => {
  const [isExpanded, setIsExpanded] = useLayoutState(false);
  const height = isExpanded ? 150 : 80;

  return (
    <Pressable onPress={() => setIsExpanded(!isExpanded)}>
      <View style={{ height, padding: 16 }}>
        <Text>{item.title}</Text>
      </View>
    </Pressable>
  );
};

useRecyclingState

const [state, setState] = useRecyclingState(
  initialState,
  dependencies,
  resetCallback
);
Similar to useState but accepts a dependency array. On change of deps, the state gets reset without an additional setState call. Useful for maintaining local item state. Also includes useLayoutState functionality. Example:
import { useRecyclingState } from "@shopify/flash-list";

const GridItem = ({ item }) => {
  const [isExpanded, setIsExpanded] = useRecyclingState(
    false,
    [item.id],
    () => {
      console.log("State reset for new item");
      // Reset scroll positions of nested lists if needed
    }
  );

  return (
    <Pressable onPress={() => setIsExpanded(!isExpanded)}>
      <View style={{ height: isExpanded ? 100 : 50 }}>
        <Text>{item.title}</Text>
      </View>
    </Pressable>
  );
};

useMappingHelper

const { getMappingKey } = useMappingHelper();
Returns a function that helps create a mapping key for items when using .map() in your render methods. This ensures optimal performance by providing consistent keys that work with the recycling system. Parameters:
  • index (number): The index of the item in the array
  • itemKey (string | number | bigint): A unique identifier for the item
Example:
import { useMappingHelper } from "@shopify/flash-list";

const MyComponent = ({ items }) => {
  const { getMappingKey } = useMappingHelper();

  return (
    <View>
      {items.map((item, index) => (
        <Text key={getMappingKey(index, item.id)}>{item.title}</Text>
      ))}
    </View>
  );
};
Use useMappingHelper whenever you need to map over arrays inside FlashList item components to ensure proper recycling.

useFlashListContext

const context = useFlashListContext();
Exposes helpers to easily access the ref of FlashList and its ScrollView. Ideal for use within child components or CellRendererComponent.

FlashList Methods

These methods are available on the FlashList ref:

scrollToIndex

flashListRef.current?.scrollToIndex({
  animated: true,
  index: 10,
  viewOffset: 0,
  viewPosition: 0,
});

scrollToItem

flashListRef.current?.scrollToItem({
  animated: true,
  item: myItem,
  viewPosition: 0,
});

scrollToOffset

flashListRef.current?.scrollToOffset({
  animated: true,
  offset: 500,
});

scrollToEnd

flashListRef.current?.scrollToEnd({ animated: true });

scrollToTop

flashListRef.current?.scrollToTop({ animated: true });

prepareForLayoutAnimationRender

flashListRef.current?.prepareForLayoutAnimationRender();
Run this method before running layout animations. This disables recycling for the next frame so that layout animations run smoothly.
Avoid using this when making large changes to the data as the list might draw too much. Single item insertions or deletions should animate smoothly.

getVisibleIndices

const indices: number[] = flashListRef.current?.getVisibleIndices();
Returns an array of indices that are currently visible in the list.

Unsupported FlatList Props

The following FlatList props are not implemented:
  • columnWrapperStyle
  • debug
  • listKey
  • disableVirtualization
  • getItemLayout
  • initialNumToRender
  • maxToRenderPerBatch
  • updateCellsBatchingPeriod
  • onScrollToIndexFailed
  • windowSize
These props bring no value to FlashList due to differences in the underlying implementation.

Build docs developers (and LLMs) love