Skip to main content

FlatList

ScrollViews are definitely handy for displaying long content, but if you're ever in a position where you:

  1. have an array of items you need to map over to render
  2. are rendering a full screen list

Then you should be using a FlatList. Not only is it more feature-rich, with built-in pull-to-refresh, scroll-to-index, header and footer support, the most important feature is that it is optimized for rendering large lists. In particular it does not render the components that are nowhere near being seen on your screen.

Use a FlatList

A FlatList has a data prop where you pass in your array of items to map over, and a renderItem prop where you define how each item is rendered. There is also a keyExtractor which lets you define a function to extract the unique key from your data (but if your data consists of objects that have either a key or an id field, then that is used automatically).

The TextInput we created earlier can be passed in as a ListHeaderComponent prop, stickyHeaderIndices and contentContainerStyle work the same way as for the ScrollView.

Update: app/index.tsx
@@ -1,4 +1,4 @@
-import { StyleSheet, TextInput, View, ScrollView } from "react-native";
+import { StyleSheet, TextInput, FlatList } from "react-native";
import { theme } from "../theme";
import { ShoppingListItem } from "../components/ShoppingListItem";
import { useState } from "react";
@@ -30,23 +30,23 @@ export default function App() {
};

return (
- <ScrollView
+ <FlatList
+ ListHeaderComponent={
+ <TextInput
+ value={value}
+ style={styles.textInput}
+ onChangeText={setValue}
+ placeholder="E.g Coffee"
+ onSubmitEditing={handleSubmit}
+ returnKeyType="done"
+ />
+ }
+ data={shoppingList}
style={styles.container}
contentContainerStyle={styles.contentContainer}
stickyHeaderIndices={[0]}
- >
- <TextInput
- value={value}
- style={styles.textInput}
- onChangeText={setValue}
- placeholder="E.g Coffee"
- onSubmitEditing={handleSubmit}
- returnKeyType="done"
- />
- {shoppingList.map((item) => (
- <ShoppingListItem name={item.name} key={item.id} />
- ))}
- </ScrollView>
+ renderItem={({ item }) => <ShoppingListItem name={item.name} />}
+ ></FlatList>
);
}

List Empty

Let's not remove out initial data and start with an empty list. We can pass a component into the ListEmptyComponent prop which will get rendered automatically when the data array is empty.

Update: app/index.tsx
@@ -1,4 +1,4 @@
-import { StyleSheet, TextInput, FlatList } from "react-native";
+import { StyleSheet, TextInput, FlatList, View, Text } from "react-native";
import { theme } from "../theme";
import { ShoppingListItem } from "../components/ShoppingListItem";
import { useState } from "react";
@@ -35,6 +35,11 @@ export default function App() {
returnKeyType="done"
/>
}
+ ListEmptyComponent={
+ <View style={styles.listEmptyContainer}>
+ <Text>Your shopping list is empty</Text>
+ </View>
+ }
data={shoppingList}
style={styles.container}
contentContainerStyle={styles.contentContainer}
@@ -63,4 +68,9 @@ const styles = StyleSheet.create({
marginBottom: 12,
backgroundColor: theme.colorWhite,
},
+ listEmptyContainer: {
+ justifyContent: "center",
+ alignItems: "center",
+ marginVertical: 18,
+ },
});

Checkpoint

AndroidiOS