Episode ini membahas list dan scroll yang efisien: FlatList dan SectionList dengan keyExtractor, getItemLayout, dan windowing, onEndReached untuk infinite scroll, serta optimasi render dengan memo dan key yang stabil.

Feed media sosial, daftar produk, dan chat punya satu kesamaan: data yang panjangnya bisa ribuan item. Jika kalian me-render semuanya sekaligus, aplikasi akan tersendat karena memory dan UI Thread bekerja di luar kendali.
Episode 8 membahas cara menyajikan list panjang dengan efisien: FlatList dan SectionList dengan keyExtractor, getItemLayout, dan windowing, onEndReached untuk infinite scroll, lalu optimasi render dengan memo dan key yang stabil. Ini fondasi performa yang akan dilanjutkan di episode 18.
ScrollView me-render semua anak sekaligus — cocok untuk konten statis dengan jumlah item sedikit. Untuk data panjang, pakai FlatList yang menerapkan virtualisasi: hanya item yang mendekati area tampil yang di-render, sisanya di-recycle saat di-scroll keluar.
import { FlatList, View, Text } from "react-native";
<FlatList
data={posts}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
</View>
)}
initialNumToRender={10}
windowSize={5}
/>initialNumToRender={10} mengontrol berapa item pertama yang dirender, dan windowSize menentukan berapa unit tinggi layar di sekitar area tampil yang tetap di-render. Keduanya membatasi kerja awal saat list dibuka.
keyExtractor memberi identitas unik tiap item. Tanpa key yang stabil, React kesulitan melacak item saat data berubah — scroll jadi melompat dan state item tertukar. Pakai id dari server, bukan index, karena index berubah saat item dihapus atau ditambah.
keyExtractor={(item) => item.id}Jika semua item punya tinggi tetap, beri tahu FlatList lewat getItemLayout agar lompatan scroll seperti scroll-to-index bekerja akurat tanpa mengukur:
const ITEM_HEIGHT = 56;
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}SectionList menambahkan grup dan header di atas FlatList — cocok untuk daftar kontak per huruf atau produk per kategori:
import { SectionList, Text } from "react-native";
<SectionList
sections={[
{ title: "A", data: ["Apel", "Alpukat"] },
{ title: "B", data: ["Belimbing"] },
]}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Text>{item}</Text>}
renderSectionHeader={({ section }) => <Text>{section.title}</Text>}
/>SectionList menerima prop yang sama dengan FlatList: initialNumToRender, windowSize, dan maxToRenderPerBatch. Untuk ribuan item, kombinasi nilai kecil pada initialNumToRender dan wajar pada windowSize menjaga scroll tetap 60 fps.
Pola umpan berita: muat halaman berikutnya saat user mendekati ujung list. onEndReached dipanggil ketika jarak scroll dari ujung kurang dari onEndReachedThreshold (fraksi dari panjang list):
const [halaman, setHalaman] = useState(1);
const [posts, setPosts] = useState([]);
function muatLagi() {
setHalaman((p) => {
ambilPostingan(p + 1).then((baru) => {
setPosts((lama) => [...lama, ...baru]);
});
return p + 1;
});
}
<FlatList
data={posts}
onEndReached={muatLagi}
onEndReachedThreshold={0.5}
ListFooterComponent={() => <Text>Memuat...</Text>}
/>onEndReached bisa terpanggil beberapa kali saat user menahan scroll di ujung. Beri penjaga agar request tidak duplikat — misalnya flag sedangMemuat yang hanya direset setelah respons datang.
Setiap perubahan data parent me-render ulang seluruh anak. Bungkus item list dengan memo agar komponen hanya re-render saat props-nya berubah:
import React, { memo } from "react";
import { Pressable, Text } from "react-native";
export const ItemList = memo(function ItemList({ item, onPress }) {
return (
<Pressable onPress={onPress}>
<Text>{item.title}</Text>
</Pressable>
);
});memo saja belum cukup jika prop onPress dibuat ulang setiap render. Stabilkan dengan useCallback — kita bahas di episode 5 — agar referensi fungsi sama antar render.
Jangan menulis renderItem inline di dalam JSX jika tidak perlu. Fungsi baru setiap render menghilangkan manfaat memo. Definisikan renderItem di luar komponen atau bungkus dengan useCallback yang dependency-nya minimal.
Warning
Jangan pakai index sebagai key untuk list yang bisa disisipkan atau dihapus item-nya. Index berubah dan React menganggap item berpindah, menyebabkan state visual tertukar. Gunakan id unik dari data atau kombinasikan dengan field lain.
Episode 8 membuat list panjang terasa ringan: FlatList dan SectionList dengan virtualisasi, keyExtractor dan getItemLayout untuk akurasi, onEndReached untuk infinite scroll, serta memo dan key stabil untuk mengurangi re-render.
Inti yang harus dibawa pulang:
ScrollView untuk konten pendek; FlatList untuk data panjang.getItemLayout mempercepat lompatan scroll saat tinggi item tetap.onEndReached untuk infinite scroll, lengkapi dengan penjaga request ganda.memo dan useCallback memangkas re-render yang tidak perlu.Di episode 9 selanjutnya kita akan membahas AsyncStorage dan local persistence: penyimpanan key-value dengan AsyncStorage, SQLite dan MMKV untuk data besar, enkripsi data sensitif, serta pola offline-first dengan queue dan strategi sinkronisasi.