React Native Academy · Pelajaran

Membangun Aplikasi Daftar Kontak

Gabungkan SectionList, header bagian alfabetis, filter pencarian, dan fitur tarik untuk menyegarkan guna membangun layar kontak realistis dengan performa gulir yang lancar.

Pelajaran 4 dari 413 langkah

Membangun Aplikasi Daftar Kontak adalah pelajaran React Native Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar React Native Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus React Native Academy mencakup 4 pelajaran total.

Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.

App Overview: Contacts List

In this lesson you will build a realistic contacts list screen that combines everything from the FlatList and SectionList lessons. The app will display contacts grouped alphabetically, support a search filter, allow pull-to-refresh, and maintain smooth performance even with hundreds of entries.

Defining the Contacts Data

Start with a static array of contact objects. In a real app this would come from the device's contacts API or a remote server. Each contact has an id, name, and phone. A unique numeric or string ID is essential for the keyExtractor.

const CONTACTS = [
  { id: '1', name: 'Alice Brown', phone: '+1-555-0101' },
  { id: '2', name: 'Andrew Chen', phone: '+1-555-0102' },
  { id: '3', name: 'Bob Davis', phone: '+1-555-0201' },
  { id: '4', name: 'Carol Evans', phone: '+1-555-0301' },
  // ... more contacts
];

Search Filter State

Add a searchQuery state variable and filter the contacts array before grouping. The filter converts both the query and contact name to lowercase for a case-insensitive match. Wrap the filtering and grouping in useMemo so it only recomputes when the contacts or query changes.

const [searchQuery, setSearchQuery] = useState('');

const filteredContacts = useMemo(() => {
  if (!searchQuery) return CONTACTS;
  return CONTACTS.filter((c) =>
    c.name.toLowerCase().includes(searchQuery.toLowerCase())
  );
}, [searchQuery]);

Grouping Contacts Alphabetically

Convert the filtered flat array into the SectionList sections format. Reduce the contacts into a map keyed by the first letter, then sort the keys and map them to section objects. This transformation runs inside useMemo alongside the filter for a single computed value.

const sections = useMemo(() => {
  const map = filteredContacts.reduce((acc, contact) => {
    const letter = contact.name[0].toUpperCase();
    if (!acc[letter]) acc[letter] = [];
    acc[letter].push(contact);
    return acc;
  }, {});
  return Object.keys(map).sort().map((key) => ({
    title: key,
    data: map[key],
  }));
}, [filteredContacts]);

Search Bar Component

Render a TextInput above the SectionList as the ListHeaderComponent so it scrolls with the list. Bind it to searchQuery state with onChangeText. Use the clearButtonMode prop on iOS to show a native clear button inside the input.

const SearchBar = () => (
  <TextInput
    style={styles.searchBar}
    placeholder='Search contacts...'
    value={searchQuery}
    onChangeText={setSearchQuery}
    clearButtonMode='while-editing'
  />
);

Contact Row Component

Build a memoized row component using React.memo to prevent unnecessary re-renders. The row shows the contact's initials in a colored avatar circle and their name and phone number on the right. Memoizing the row component is critical for smooth scrolling with hundreds of contacts.

const ContactRow = React.memo(({ item }) => (
  <View style={styles.row}>
    <View style={styles.avatar}>
      <Text style={styles.initials}>{item.name[0]}</Text>
    </View>
    <View>
      <Text style={styles.name}>{item.name}</Text>
      <Text style={styles.phone}>{item.phone}</Text>
    </View>
  </View>
));

Section Header Component

The alphabetic section header is a simple View with the letter. Give it a distinct background color and sticky behavior so it stays visible as the user scrolls through each letter group. Keep the component small and memoized since it renders once per letter.

const SectionHeader = ({ section }) => (
  <View style={styles.sectionHeader}>
    <Text style={styles.sectionTitle}>{section.title}</Text>
  </View>
);

Pull-to-Refresh Integration

Simulate refreshing by introducing a refreshing state. On refresh, clear the search query (so users see all contacts again), wait briefly to simulate a network call, then set refreshing to false. In a real app you would re-fetch from the device contacts API or the server.

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

const onRefresh = () => {
  setRefreshing(true);
  setSearchQuery('');
  setTimeout(() => setRefreshing(false), 1000);
};

Empty State When No Results

When the filtered sections array is empty (no contacts match the search), display an informative empty state using ListEmptyComponent. Tell the user no contacts match their query and suggest they clear the search. This is far better than showing a blank screen.

const ListEmpty = () => (
  <View style={styles.empty}>
    <Text>No contacts found for '{searchQuery}'</Text>
    <Button title='Clear Search' onPress={() => setSearchQuery('')} />
  </View>
);

Assembling the Full Screen

Combine all the pieces: SectionList with the sections data, memoized renderItem, renderSectionHeader, keyExtractor, sticky headers, pull-to-refresh, and ListHeaderComponent for the search bar. The result is a production-quality contacts screen.

export default function ContactsScreen() {
  return (
    <SectionList
      sections={sections}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <ContactRow item={item} />}
      renderSectionHeader={({ section }) => <SectionHeader section={section} />}
      stickySectionHeadersEnabled
      refreshing={refreshing}
      onRefresh={onRefresh}
      ListHeaderComponent={SearchBar}
      ListEmptyComponent={ListEmpty}
    />
  );
}

Navigating to a Contact Detail Screen

Make each row tappable by wrapping the ContactRow in a TouchableOpacity that calls navigation.navigate('ContactDetail', { contactId: item.id }). The detail screen reads the ID from route.params and fetches the full contact data, following the React Navigation pattern you learned earlier.

const ContactRow = React.memo(({ item, onPress }) => (
  <TouchableOpacity onPress={() => onPress(item)} style={styles.row}>
    <View style={styles.avatar}>
      <Text style={styles.initials}>{item.name[0]}</Text>
    </View>
    <View>
      <Text style={styles.name}>{item.name}</Text>
      <Text style={styles.phone}>{item.phone}</Text>
    </View>
  </TouchableOpacity>
));

Quick Check

Test your understanding of the Contacts List App architecture from this lesson.

Lesson Recap

In this lesson you learned: combine SectionList, search filtering, and useMemo for an efficient contacts screen, memoize row components with React.memo to maintain scroll performance, and integrate pull-to-refresh and empty states for a polished UX. Next up we dive into the useRef hook and mutable values.

Gratis untuk memulai

Belajar JavaScript dengan tutor AI — gratis

Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.

Kursus
30
Pelajaran
120

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Membangun Aplikasi Daftar Kontak” gratis?

Ya — teks lengkap “Membangun Aplikasi Daftar Kontak” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus React Native Academy, upgrade ke CoddyKit PRO. Kursus React Native Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Membangun Aplikasi Daftar Kontak”?

Gabungkan SectionList, header bagian alfabetis, filter pencarian, dan fitur tarik untuk menyegarkan guna membangun layar kontak realistis dengan performa gulir yang lancar. Kamu berlatih React Native Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai React Native Academy?

Tidak diperlukan pengalaman sebelumnya. React Native Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Membangun Aplikasi Daftar Kontak” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran React Native Academy ini?

Ya. Setiap pelajaran React Native Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Data FlatList, renderItem, dan keyExtractor
  2. Tarik untuk Menyegarkan dan Memuat Lebih Banyak
  3. SectionList dengan Header
  4. Membangun Aplikasi Daftar Kontak
← Kembali ke React Native Academy