Master React Native FlatList
Last update: 2025-04-24The FlatList
component is one of the most important building blocks in React Native. Whether you’re building a social media feed, a product list, or any scrollable content - FlatList is your go-to solution.
In this guide, you’ll learn everything about FlatList with practical examples that you can use in your apps right away.
Basic FlatList Usage
Let’s start with a simple example of how to use FlatList:
import { FlatList, Text, View } from 'react-native';
const data = [
{ id: '1', title: 'First Item' },
{ id: '2', title: 'Second Item' },
{ id: '3', title: 'Third Item' }
];
export default function App() {
const renderItem = ({ item }) => (
<View style={{ padding: 20, borderBottomWidth: 1 }}>
<Text>{item.title}</Text>
</View>
);
return <FlatList data={data} renderItem={renderItem} keyExtractor={(item) => item.id} />;
}
In this example:
- We import the necessary components from React Native
- Define an array of data with unique IDs
- Create a
renderItem
function that returns the UI for each item - Use
keyExtractor
to specify how to get the unique key for each item
Pull to Refresh
Adding pull-to-refresh functionality is super easy with FlatList:
export default function App() {
const [refreshing, setRefreshing] = useState(false);
const [data, setData] = useState([
{ id: '1', title: 'First Item' },
{ id: '2', title: 'Second Item' }
]);
const onRefresh = useCallback(() => {
setRefreshing(true);
// Simulate fetching new data
setTimeout(() => {
setData([{ id: '3', title: 'New Item' }, ...data]);
setRefreshing(false);
}, 1000);
}, [data]);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
refreshing={refreshing}
onRefresh={onRefresh}
/>
);
}
This implementation:
- Uses
useState
to manage the refreshing state and data - Implements
onRefresh
to handle the refresh action - Adds the
refreshing
andonRefresh
props to FlatList
Infinite Scrolling
One of the most common use cases is implementing infinite scrolling:
export default function App() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const fetchData = async () => {
if (loading) return;
setLoading(true);
try {
// Replace with your API endpoint
const response = await fetch(`https://api.example.com/items?page=${page}`);
const newData = await response.json();
setData([...data, ...newData]);
setPage(page + 1);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
const renderFooter = () => {
if (!loading) return null;
return (
<View style={{ padding: 20 }}>
<ActivityIndicator size="large" />
</View>
);
};
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
onEndReached={fetchData}
onEndReachedThreshold={0.5}
ListFooterComponent={renderFooter}
/>
);
}
This implementation includes:
- State management for data, loading state, and pagination
- A
fetchData
function that loads more items when needed onEndReached
prop to trigger loading when reaching the endonEndReachedThreshold
to determine when to load more (0.5 means 50% from the end)- A footer component to show loading state
Performance Optimization
To make your FlatList perform better, especially with large lists:
export default function App() {
const renderItem = useCallback(
({ item }) => (
<View style={{ padding: 20, borderBottomWidth: 1 }}>
<Text>{item.title}</Text>
</View>
),
[]
);
const getItemLayout = useCallback(
(data, index) => ({
length: 60, // Height of each item
offset: 60 * index,
index
}),
[]
);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
getItemLayout={getItemLayout}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={5}
initialNumToRender={10}
/>
);
}
These optimizations include:
useCallback
for memoizing therenderItem
functiongetItemLayout
to pre-calculate dimensions (helps with scrolling performance)removeClippedSubviews
to detach off-screen viewsmaxToRenderPerBatch
to limit the number of items rendered per batchwindowSize
to control the number of screens worth of content renderedinitialNumToRender
to set how many items to render initially
Section Lists
For grouped data, you can use SectionList, FlatList’s cousin:
import { SectionList, Text, View } from 'react-native';
const DATA = [
{
title: 'Main dishes',
data: ['Pizza', 'Burger', 'Risotto']
},
{
title: 'Sides',
data: ['French Fries', 'Onion Rings', 'Salad']
}
];
export default function App() {
return (
<SectionList
sections={DATA}
renderItem={({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item}</Text>
</View>
)}
renderSectionHeader={({ section: { title } }) => (
<View style={{ backgroundColor: '#f0f0f0', padding: 10 }}>
<Text style={{ fontWeight: 'bold' }}>{title}</Text>
</View>
)}
keyExtractor={(item, index) => item + index}
/>
);
}
SectionList is perfect when you need to:
- Display data in logical groups
- Have sticky section headers
- Handle different types of content in one list
Conclusion
FlatList is a powerful component that can handle most list-related use cases in React Native. With these examples, you can:
- Create basic lists with custom rendering
- Implement pull-to-refresh functionality
- Add infinite scrolling
- Optimize performance for large lists
- Work with sectioned data
Remember to always consider performance implications when working with large lists, and use the optimization techniques we covered when needed.
Want to learn more about React Native? Check out our Zero to Hero React Native Mission where we dive deep into building professional React Native applications!