How to Create a React Native Grid Using FlatList: Complete Implementation Guide
Use the FlatList component with the numColumns prop to create a react native grid layout that efficiently renders scrollable columns.
React Native provides the FlatList component as the modern replacement for the legacy ListView, offering built-in virtualization and performance optimizations. When you need to display data in a react native grid format rather than a single column, FlatList eliminates the need for external libraries by exposing a simple numColumns prop that transforms the vertical list into a multi-column layout.
How FlatList Implements Grid Layout in React Native
Under the hood, FlatList is built on top of VirtualizedList, which efficiently recycles rows as they scroll off-screen. When you specify the numColumns prop, each rendered item gets wrapped in a row container that contains exactly numColumns children. This layout logic stays within the core library, meaning you only need to provide a function that renders a single cell.
The virtualization engine maintains a windowSize that determines how many items to render outside the visible viewport. For grid layouts, this is particularly important because each "row" in the virtualized view actually contains multiple data items.
React Native Grid Implementation: Code Examples
Basic Two-Column Grid
This example demonstrates the minimal configuration required to render a react native grid with two columns:
import React from 'react';
import {FlatList, View, Text, StyleSheet, Dimensions} from 'react-native';
const DATA = Array.from({length: 30}, (_, i) => ({
id: `${i}`,
title: `Item ${i + 1}`,
}));
export default function SimpleGrid() {
const numColumns = 2;
const itemWidth = Dimensions.get('window').width / numColumns;
const renderItem = ({item}) => (
<View style={[styles.item, {width: itemWidth}]}>
<Text style={styles.title}>{item.title}</Text>
</View>
);
return (
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
numColumns={numColumns}
showsVerticalScrollIndicator={false}
/>
);
}
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
margin: 4,
alignItems: 'center',
justifyContent: 'center',
height: 100,
},
title: {
fontSize: 16,
},
});
Key implementation details:
numColumns={2}instructsFlatListto arrange two items per row.itemWidthis calculated so each cell fills exactly half the screen width.keyExtractorreturns a stable string ID to maintain component identity during recycling.
Grid with Spacing and Custom Separators
For production applications, you typically need controlled spacing between cells. This example uses columnWrapperStyle and ItemSeparatorComponent:
import React from 'react';
import {
FlatList,
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
const photos = [
/* an array of objects {id, uri, title} */
];
export default function PhotoGrid() {
const columns = 3;
const renderItem = ({item}) => (
<TouchableOpacity style={styles.cell}>
<View style={styles.imagePlaceholder} />
<Text style={styles.caption}>{item.title}</Text>
</TouchableOpacity>
);
const ItemSeparator = () => <View style={styles.vertSep} />;
return (
<FlatList
data={photos}
renderItem={renderItem}
keyExtractor={item => item.id}
numColumns={columns}
columnWrapperStyle={styles.row}
ItemSeparatorComponent={ItemSeparator}
contentContainerStyle={styles.container}
/>
);
}
const styles = StyleSheet.create({
container: {
padding: 8,
},
row: {
justifyContent: 'space-between',
},
cell: {
flex: 1,
margin: 4,
backgroundColor: '#eaeaea',
alignItems: 'center',
padding: 8,
},
vertSep: {
width: 8,
},
imagePlaceholder: {
width: '100%',
height: 80,
backgroundColor: '#bbb',
},
caption: {
marginTop: 4,
fontSize: 12,
},
});
Critical styling concepts:
columnWrapperStyleapplies a style to the row container that holds thenumColumnsitems.ItemSeparatorComponentinserts a vertical spacer between columns.- Using
flex: 1on each cell ensures equal width distribution regardless of device dimensions.
Responsive Grid Handling Orientation Changes
For a truly adaptive react native grid, listen to dimension changes and recalculate columns dynamically:
import React, {useState, useEffect} from 'react';
import {
FlatList,
View,
Text,
StyleSheet,
Dimensions,
} from 'react-native';
export default function ResponsiveGrid() {
const [numColumns, setNumColumns] = useState(2);
const [itemSize, setItemSize] = useState(0);
const updateLayout = () => {
const {width, height} = Dimensions.get('window');
// Switch to 3 columns in landscape, 2 in portrait
const cols = width > height ? 3 : 2;
setNumColumns(cols);
setItemSize(width / cols);
};
useEffect(() => {
updateLayout(); // initial
const sub = Dimensions.addEventListener('change', updateLayout);
return () => sub?.remove();
}, []);
const renderItem = ({item}) => (
<View style={[styles.item, {width: itemSize, height: itemSize}]}>
<Text>{item.title}</Text>
</View>
);
return (
<FlatList
data={Array.from({length: 20}, (_, i) => ({
id: `${i}`,
title: `#${i + 1}`,
}))}
renderItem={renderItem}
keyExtractor={item => item.id}
numColumns={numColumns}
/>
);
}
const styles = StyleSheet.create({
item: {
backgroundColor: '#b3e5fc',
margin: 4,
alignItems: 'center',
justifyContent: 'center',
},
});
Implementation notes:
Dimensions.addEventListenertriggers when the device rotates.- Recalculating
numColumnsforcesFlatListto re-render with the new layout. - Setting explicit
widthandheightensures square cells that adapt to the new column count.
Key Considerations for React Native Grid Performance
When implementing a react native grid, optimize for these critical concerns:
| Concern | Implementation Strategy |
|---|---|
| Item sizing | All items in a row must share the same width. Use flex: 1 on the item container or calculate width from Dimensions.get('window').width / numColumns. |
| Spacing | Add ItemSeparatorComponent for vertical gaps and columnWrapperStyle for horizontal row styling. |
| Key extraction | Provide a stable keyExtractor so recycled rows maintain component identity and state. |
| Performance | Keep initialNumToRender low, enable windowSize tuning, and avoid heavy computations inside renderItem. |
| Orientation changes | Re-calculate dimensions on the onLayout event or listen to Dimensions updates to adjust column counts dynamically. |
React Source Code Context
While FlatList lives in the React Native repository, the underlying virtualization principles mirror concepts found in the React core codebase. For example, in packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js, React DevTools renders a flat list of component owners using an itemData array and a renderer receiving {index, style} parameters—demonstrating the same recycling pattern that powers VirtualizedList.
Similarly, packages/use-sync-external-store/src/useSyncExternalStore.js provides the subscription mechanism that keeps virtualized lists synchronized with external data sources, while packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseBreadcrumbs.js illustrates performance-focused list rendering in the DevTools UI.
Summary
- Use
FlatListwithnumColumnsto create a react native grid without external dependencies. - Calculate item widths using
Dimensionsorflex: 1to ensure equal column distribution. - Implement
keyExtractorand optimizewindowSizefor smooth scrolling performance with large datasets. - Handle orientation changes by listening to
Dimensionsevents and dynamically updatingnumColumns. - Style rows with
columnWrapperStyleand add separators withItemSeparatorComponentfor professional grid spacing.
Frequently Asked Questions
What is the difference between FlatList and the old ListView in React Native?
FlatList is the modern replacement for the deprecated ListView component, offering significant performance improvements through virtualization. Unlike ListView, which rendered all rows immediately, FlatList only mounts items visible on screen plus a configurable window, recycling components as you scroll to maintain 60fps performance even with thousands of items.
How do I handle different screen sizes in a react native grid?
Calculate your item dimensions dynamically using Dimensions.get('window') and divide by your numColumns value. For responsive layouts that adapt to orientation changes, attach a listener to Dimensions.addEventListener('change', ...) and update both numColumns and item size in your component state, which triggers a re-render with the new layout.
Why are my grid items not aligning properly?
Uneven alignment typically occurs when items in the same row have different heights or when width calculations don't account for margins and padding. Ensure all items in a row share the same width by using flex: 1 or calculated dimensions, and verify that your columnWrapperStyle doesn't conflict with the internal row styling applied by FlatList.
Can I use FlatList for horizontal grids?
FlatList supports horizontal scrolling via the horizontal prop, but the numColumns prop only works with vertical lists. For a horizontal grid (items arranged in rows that scroll sideways), you would need to use ScrollView with a custom layout or a library like react-native-super-grid, as the core FlatList implementation specifically maps numColumns to vertical column layouts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →