React Native Lists and ScrollView

Almost every app shows a list of items — messages, contacts, products, or news articles. React Native offers two components for scrollable content: ScrollView for short content and FlatList for long or dynamic lists. Choosing the right one affects your app's speed significantly.

ScrollView — Simple Scrollable Container

ScrollView renders all its children at once. The entire content loads into memory before the user sees anything. This works well for short forms, settings screens, or pages with fewer than 20 items.

import { ScrollView, Text, View } from 'react-native';

export default function SettingsScreen() {
  return (
    <ScrollView contentContainerStyle={{ padding: 16 }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold' }}>Account</Text>
      <Text>Profile Settings</Text>
      <Text>Privacy</Text>
      <Text>Security</Text>
      <Text style={{ fontSize: 18, fontWeight: 'bold', marginTop: 20 }}>App</Text>
      <Text>Notifications</Text>
      <Text>Display</Text>
      <Text>Language</Text>
    </ScrollView>
  );
}

ScrollView Direction

Vertical scroll (default):        Horizontal scroll:
┌─────────┐                       ┌─────────────────────────────┐
│ Item 1  │ ▲                     │  Card 1 │ Card 2 │ Card 3  ──►
│ Item 2  │                       └─────────────────────────────┘
│ Item 3  │
│ Item 4  │ ▼
└─────────┘

Horizontal: <ScrollView horizontal={true}>...</ScrollView>

FlatList — Efficient Long Lists

FlatList only renders the items visible on screen plus a small buffer above and below. Items that scroll off screen are removed from memory. Items about to scroll into view are added. This lazy approach handles thousands of items without slowing down.

ScrollView                        FlatList
────────────────────────────────────────────────────────
Renders: ALL items at once        Renders: only visible items

┌──────────┐  ← Item 1 in RAM    ┌──────────┐  ← Item 3 in RAM
│ Item 1   │                     │ Item 3   │
│ Item 2   │                     │ Item 4   │
│ Item 3   │  ← visible area     │ Item 5   │  ← visible area
│ Item 4   │                     │ Item 6   │
│ Item 5   │  ← Item 200 in RAM  └──────────┘  ← Items 1,2,200 recycled
│ ...200   │
└──────────┘

Basic FlatList

import { FlatList, Text, View, StyleSheet } from 'react-native';

const contacts = [
  { id: '1', name: 'Alice', phone: '555-0101' },
  { id: '2', name: 'Bob',   phone: '555-0102' },
  { id: '3', name: 'Carol', phone: '555-0103' },
];

function ContactItem({ name, phone }) {
  return (
    <View style={styles.item}>
      <Text style={styles.name}>{name}</Text>
      <Text style={styles.phone}>{phone}</Text>
    </View>
  );
}

export default function ContactList() {
  return (
    <FlatList
      data={contacts}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <ContactItem name={item.name} phone={item.phone} />}
    />
  );
}
Screen:
┌──────────────────────────────┐
│ Alice                        │
│ 555-0101                     │
├──────────────────────────────┤
│ Bob                          │
│ 555-0102                     │
├──────────────────────────────┤
│ Carol                        │
│ 555-0103                     │
└──────────────────────────────┘

Three Required FlatList Props

Prop              Purpose
────────────────────────────────────────────────────────
data              The array of items to display
keyExtractor      Returns a unique string ID for each item
renderItem        A function that returns the JSX for one item

Adding a Separator Between Items

<FlatList
  data={contacts}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ContactItem {...item} />}
  ItemSeparatorComponent={() => (
    <View style={{ height: 1, backgroundColor: '#E5E5EA', marginLeft: 16 }} />
  )}
/>

Adding a Header and Footer

<FlatList
  data={contacts}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ContactItem {...item} />}
  ListHeaderComponent={
    <Text style={{ padding: 16, fontWeight: 'bold', fontSize: 20 }}>
      Contacts
    </Text>
  }
  ListFooterComponent={
    <Text style={{ padding: 16, color: '#999', textAlign: 'center' }}>
      {contacts.length} contacts total
    </Text>
  }
/>

Empty State

Show a helpful message when the list has no data to display.

<FlatList
  data={filteredContacts}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ContactItem {...item} />}
  ListEmptyComponent={
    <View style={{ alignItems: 'center', marginTop: 60 }}>
      <Text style={{ fontSize: 48 }}>🔍</Text>
      <Text style={{ color: '#999', marginTop: 8 }}>No contacts found</Text>
    </View>
  }
/>

Pull-to-Refresh

Users expect to pull the list down to refresh the content. FlatList supports this with two props.

const [refreshing, setRefreshing] = useState(false);

async function handleRefresh() {
  setRefreshing(true);
  await fetchContacts();   // re-fetch your data
  setRefreshing(false);
}

<FlatList
  data={contacts}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ContactItem {...item} />}
  refreshing={refreshing}
  onRefresh={handleRefresh}
/>

SectionList — Grouped Lists

SectionList organises items into labelled sections — like a contacts list grouped by first letter.

import { SectionList } from 'react-native';

const sections = [
  { title: 'A', data: ['Alice', 'Andrew'] },
  { title: 'B', data: ['Bob', 'Brenda'] },
  { title: 'C', data: ['Carol'] },
];

<SectionList
  sections={sections}
  keyExtractor={(item, index) => item + index}
  renderItem={({ item }) => <Text style={{ padding: 12 }}>{item}</Text>}
  renderSectionHeader={({ section: { title } }) => (
    <Text style={{ backgroundColor: '#f0f0f0', padding: 8, fontWeight: 'bold' }}>
      {title}
    </Text>
  )}
/>

Screen:
┌──────────────────────┐
│ A                    │  ← section header
│   Alice              │
│   Andrew             │
│ B                    │  ← section header
│   Bob                │
│   Brenda             │
└──────────────────────┘

Choosing the Right Component

Situation                         Best Component
──────────────────────────────────────────────────
Short form or settings screen     ScrollView
Long or dynamic list              FlatList
Grouped list (A–Z, categories)    SectionList
Horizontal card carousel          FlatList + horizontal

Summary

Use ScrollView for short content that fits within a few screens. Use FlatList for any list that could grow or already contains many items — it only renders what is visible. SectionList adds section headers for grouped data. Pull-to-refresh, empty states, and separators make your list experience feel polished and professional.

Leave a Comment