Master React Native FlatList

Last update: 2025-04-24
Type
Quick Win's logo Quick Win
Membership
🆓
Tech
TypeScript TypeScript
TypeScript
Share:

The 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 and onRefresh 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 end
  • onEndReachedThreshold 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 the renderItem function
  • getItemLayout to pre-calculate dimensions (helps with scrolling performance)
  • removeClippedSubviews to detach off-screen views
  • maxToRenderPerBatch to limit the number of items rendered per batch
  • windowSize to control the number of screens worth of content rendered
  • initialNumToRender 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!

Zero to Hero React Native Mission
Simon Grimm