Working with List Components
1. Using FlatList Component
Example: Basic FlatList Usage
import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = [
{ id: '1', name: 'Alice' },
{ id: '2', name: 'Bob' },
{ id: '3', name: 'Charlie' },
];
const renderItem = ({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item.name}</Text>
</View>
);
const MyFlatList = () => (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
);
export default MyFlatList;
| Prop | Type | Description |
|---|---|---|
| data | Array<Object> |
Array of data items to render |
| renderItem | Function |
Function that returns a React element for each item |
| keyExtractor | Function |
Function that returns a unique key for each item |
| getItemLayout | Function |
Optional function to provide item layout info for performance |
| horizontal | boolean |
Set to true for horizontal list |
| numColumns | number |
Number of columns in grid list (default: 1) |
| onEndReached | Function |
Called when list is scrolled to end |
| onRefresh | Function |
Function to handle pull-to-refresh (requires refreshing) |
| refreshing | boolean |
Indicates if list is currently refreshing (requires onRefresh) |
| ListHeaderComponent | React.Component |
Component to render at the top of the list |
| ListFooterComponent | React.Component |
Component to render at the bottom of the list |
Note:
FlatList is optimized for large lists and only renders visible items, improving performance.
Example: FlatList with Horizontal Layout
import React from 'react';
import { FlatList, Text, View } from 'react-native';
const horizontalData = [
{ id: '1', title: 'Item 1' },
{ id: '2', title: 'Item 2' },
{ id: '3', title: 'Item 3' },
];
const HorizontalFlatList = () => (
<FlatList
data={horizontalData}
renderItem={({ item }) => (
<View style={{ width: 100, padding: 10 }}>
<Text>{item.title}</Text>
</View>
)}
horizontal={true}
keyExtractor={item => item.id}
/>
);
export default HorizontalFlatList;
2. Using SectionList Component
| Property | Description | Default | Notes |
|---|---|---|---|
| sections | An array of objects containing data for each section | Required | Each object must include a data array and optionally a key |
| renderSectionHeader | A function that renders the header for each section | Optional | Receives {section} as argument |
| renderItem | A function that renders each item in a section | Required | Receives {item, section, index} as argument |
| keyExtractor | A function that extracts a unique key for each item | Optional | If not provided, uses item.key or falls back to index |
| stickySectionHeadersEnabled | Whether to stick section headers to the top of the list | false |
Set to true for sticky headers |
Example: Basic SectionList Usage
import React from 'react';
import { SectionList, Text, View } from 'react-native';
const data = [
{
title: 'Fruits',
data: ['Apple', 'Banana', 'Orange'],
},
{
title: 'Vegetables',
data: ['Carrot', 'Broccoli', 'Spinach'],
},
];
const renderItem = ({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item}</Text>
</View>
);
const renderSectionHeader = ({ section }) => (
<View style={{ backgroundColor: '#f0f0f0', padding: 10 }}>
<Text style={{ fontWeight: 'bold' }}>{section.title}</Text>
</View>
);
const MySectionList = () => (
<SectionList
sections={data}
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
/>
);
export default MySectionList;
Note: The
SectionList component is optimized for large lists with sections, offering better performance than FlatList when dealing with grouped data.
3. Implementing List Optimization
Example: Using FlatList with keyExtractor
import { FlatList } from 'react-native';
const data = [
{ id: '1', name: 'John' },
{ id: '2', name: 'Jane' },
{ id: '3', name: 'Bob' },
];
const renderItem = ({ item }) => (
<View style={styles.item}>
<Text>{item.name}</Text>
</View>
);
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
| Property | Description | Default |
|---|---|---|
| data | Array of items to render | None |
| renderItem | Function that renders a single item | None |
| keyExtractor | Function that extracts a unique key for each item | Uses index as key (not recommended) |
| initialNumToRender | Number of items to render initially | 10 |
| maxToRenderPerBatch | Max items to render per batch | 10 |
| windowSize | How far to render items from the current scroll position | 21 |
Note: Using
keyExtractor is crucial for performance, especially when items can be reordered or updated.
Example: Using SectionList for grouped lists
import { SectionList } from 'react-native';
const sections = [
{
title: 'A',
data: ['Apple', 'Avocado'],
},
{
title: 'B',
data: ['Banana', 'Blueberry'],
},
];
const renderSectionHeader = ({ section }) => (
<View style={styles.header}>
<Text>{section.title}</Text>
</View>
);
<SectionList
sections={sections}
renderSectionHeader={renderSectionHeader}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
/>
| Property | Description | Default |
|---|---|---|
| sections | Array of section objects with title and data | None |
| renderSectionHeader | Function that renders a section header | None |
| renderItem | Function that renders a single item | None |
| keyExtractor | Function that extracts a unique key for each item | Uses index as key (not recommended) |
Optimization Workflow
- Use
FlatListinstead ofScrollViewwithViewfor large lists - Implement
keyExtractorto ensure stable keys for items - Optimize
renderItemto avoid unnecessary re-renders - Use
getItemLayoutfor lists with uniform item sizes (optional) - Consider
SectionListfor grouped lists with headers
4. Handling Pull to Refresh
| Property | Description | Default | Notes |
|---|---|---|---|
| refreshing | Boolean indicating whether the refresh control is currently refreshing | false |
Must be controlled by state in your component |
| onRefresh | Function called when the user pulls to refresh | null |
Should update refreshing state to true, then fetch data and set it back to false |
| refreshColor | Color of the refresh indicator (Android only) | #000000 |
Can be any valid color string or hex value |
| tintColor | Color of the refresh indicator (iOS only) | #000000 |
Can be any valid color string or hex value |
| title | Text to display during refresh (iOS only) | null |
Only visible on iOS devices |
Example: Pull to Refresh Implementation
import React, { useState } from 'react';
import { FlatList, View, Text, RefreshControl } from 'react-native';
const MyList = () => {
const [data, setData] = useState([]);
const [refreshing, setRefreshing] = useState(false);
const onRefresh = React.useCallback(() => {
setRefreshing(true);
// Simulate API call
setTimeout(() => {
setData([1, 2, 3, 4, 5]);
setRefreshing(false);
}, 1000);
}, []);
return (
<FlatList
data={data}
keyExtractor={(item) => item.toString()}
renderItem={({ item }) => <Text>{item}</Text>}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor="#000000"
/>
}
/>
);
};
export default MyList;
Note: The
refreshing prop must be controlled by state to ensure the refresh indicator animates correctly.
Warning: On Android, the
refreshColor property is required to show the indicator.
5. Implementing Infinite Scroll
Infinite scroll is a technique used to load and display content dynamically as the user scrolls, improving performance by only rendering visible items.
| Property | Description | Values |
|---|---|---|
| onEndReached | Callback function when the user scrolls to the end of the list | () => void |
| onEndReachedThreshold | Distance from the end of the list (in pixels) to trigger loading | number |
| List Component | React Native component used to implement infinite scroll | FlatList, SectionList |
Example: Basic Infinite Scroll with FlatList
import React, { useState } from 'react';
import { FlatList, View, Text } from 'react-native';
const InfiniteScrollExample = () => {
const [data, setData] = useState(Array.from({ length: 20 }, (_, i) => ({ id: i, text: `Item ${i}` })));
const [loading, setLoading] = useState(false);
const loadMore = () => {
if (loading) return;
setLoading(true);
setTimeout(() => {
const newData = Array.from({ length: 10 }, (_, i) => ({
id: data.length + i,
text: `Item ${data.length + i}`
}));
setData([...data, ...newData]);
setLoading(false);
}, 1000);
};
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <Text style={{ padding: 10 }}>{item.text}</Text>}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
);
};
export default InfiniteScrollExample;
Note: The
onEndReachedThreshold value is a number between 0 and 1, representing the percentage of the list that must be scrolled to trigger loading.
Warning: Ensure that
onEndReached is not called repeatedly due to scroll events. Implement debouncing or loading state to prevent unnecessary API calls.
6. Using List Header and Footer
Example: Basic List with Header and Footer
import React from 'react';
import { FlatList, Text, View } from 'react-native';
const renderItem = ({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item.name}</Text>
</View>
);
const MyList = () => {
const data = [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
];
return (
<FlatList
data={data}
renderItem={renderItem}
ListHeaderComponent={
<View style={{ padding: 10, backgroundColor: '#f0f0f0' }}>
<Text>List Header</Text>
</View>
}
ListFooterComponent={
<View style={{ padding: 10, backgroundColor: '#f0f0f0' }}>
<Text>List Footer</Text>
</View>
}
/>
);
};
export default MyList;
| Prop | Description | Values | Notes |
|---|---|---|---|
| ListHeaderComponent | Component to render at the top of the list | React.Component |
Rendered before the first item |
| ListFooterComponent | Component to render at the bottom of the list | React.Component |
Rendered after the last item |
Note: These components are rendered outside the scrollable area and do not scroll with the list items.
7. Handling Empty States
Example: Basic Empty State Component
{`import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const EmptyState = ({ message }) => (
<View style={styles.container}>
<Text style={styles.message}>{message}</Text>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
message: {
fontSize: 16,
textAlign: 'center',
color: '#666',
},
});
export default EmptyState;`}
| Property | Description | Default |
|---|---|---|
| message | Text to display when list is empty | null |
| icon | Optional icon component to show | null |
| actionButton | Optional button to trigger action | null |
Note: Empty states should provide clear guidance or a call to action to improve user experience.
Empty State Implementation Workflow
- Create a reusable
EmptyStatecomponent - Conditionally render it when list data is empty
- Customize message and actions based on context
8. Using VirtualizedList Component
The VirtualizedList component is a core building block in React Native for efficiently rendering large lists of data. It only renders the items that are currently visible on screen, significantly improving performance for large datasets.
| Prop | Description | Default | Type |
|---|---|---|---|
| data | Array of data to render | null |
Array |
| renderItem | Function that renders a single item | null |
Function |
| keyExtractor | Function to extract a unique key for each item | null |
Function |
| getItemLayout | Function to provide item layout information (optional but recommended for performance) | null |
Function |
| initialNumToRender | Number of items to render initially | 10 |
number |
| maxToRenderPerBatch | Maximum number of items to render in each batch | 10 |
number |
| windowSize | Number of items to render beyond the visible area | 2 |
number |
| onEndReached | Callback when the list is scrolled to the end | null |
Function |
| onEndReachedThreshold | Distance from the end to trigger onEndReached |
0.5 |
number |
Example: Basic VirtualizedList Usage
import React from 'react';
import { VirtualizedList, Text, View } from 'react-native';
const DATA = Array.from({ length: 1000 }, (_, i) => ({
id: i.toString(),
text: `Item ${i}`,
}));
const renderItem = ({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item.text}</Text>
</View>
);
const VirtualizedListExample = () => (
<VirtualizedList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
/>
);
export default VirtualizedListExample;
Note: For better performance, it's recommended to provide
getItemLayout if items have a fixed height.
Example: Using getItemLayout for Performance
const getItemLayout = (data, index) => ({
length: 50,
offset: 50 * index,
index,
});
// In VirtualizedList:
<VirtualizedList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
getItemLayout={getItemLayout}
/>
9. Implementing Item Separators
| Property | Description | Usage |
|---|---|---|
| ItemSeparatorComponent | Component to render between items | ItemSeparatorComponent={() => <View style={{ height: 1, backgroundColor: '#ccc' }} />} |
| SectionSeparatorComponent | Component to render between sections | SectionSeparatorComponent={() => <View style={{ height: 1, backgroundColor: '#999' }} />} |
Example: Using ItemSeparatorComponent
import React from 'react';
import { FlatList, View, Text } from 'react-native';
const data = [
{ id: '1', name: 'Item One' },
{ id: '2', name: 'Item Two' },
{ id: '3', name: 'Item Three' },
];
const Separator = () => (
<View style={{ height: 1, backgroundColor: '#ccc' }} />
);
const renderItem = ({ item }) => (
<View style={{ padding: 10 }}>
<Text>{item.name}</Text>
</View>
);
const MyList = () => (
<FlatList
data={data}
renderItem={renderItem}
ItemSeparatorComponent={Separator}
/>
);
export default MyList;
Note:
ItemSeparatorComponent is not rendered for the first item.10. Optimizing List Performance
Example: Using key prop to optimize list rendering
const ListComponent = () => {
const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];
return (
<FlatList
data={items}
renderItem={({ item }) => <Text>{item.name}</Text>}
keyExtractor={item => item.id.toString()}
/>
);
};
| Optimization | Description | Impact |
|---|---|---|
| keyExtractor | Unique identifier for list items | Improves rendering performance by avoiding re-renders |
| FlatList vs ScrollView | FlatList only renders visible items | Reduces memory usage and improves performance |
| List item memoization | Use React.memo for list items |
Prevents unnecessary re-renders of unchanged items |
Note: Using
keyExtractor is crucial for performance. Without it, React Native may re-render all items when the list changes.
11. Using FlashList for Performance
Example: Basic FlashList Usage
import FlashList from '@shopify/flash-list';
const data = Array.from({ length: 1000 }, (_, i) => ({
id: i.toString(),
name: `Item ${i}`,
}));
const renderItem = ({ item }) => (
<View style={styles.item}>
<Text>{item.name}</Text>
</View>
);
<FlashList
data={data}
renderItem={renderItem}
estimatedItemSize={50}
keyExtractor={(item) => item.id}
/>
| Property | Description | Default | Notes |
|---|---|---|---|
| data | Array of data to render | null |
Required |
| renderItem | Function to render each item | null |
Required |
| estimatedItemSize | Estimated height of each item | 50 |
Improves performance |
| keyExtractor | Function to extract unique keys | item => item.id |
Required for performance |
| maxToRenderPerBatch | Max items to render per batch | 10 |
Controls rendering frequency |
| windowSize | Number of items to render ahead | 21 |
Improves scroll smoothness |
Note: FlashList is optimized for large lists and provides better performance than ScrollView or FlatList for large datasets.