FlatList — katta ro'yxatlar, keyExtractor, pull-to-refresh
Muammodan boshlaylik
Katalogda 2000 ta mahsulot. ScrollView + map bilan chizdingiz (8-dars). Natija:
- Ekran 4 soniya oq turadi — 2000 ta karta va 2000 ta rasm birdaniga yaratilmoqda
- Scroll uzilib-uzilib ketadi
- Eski telefonlarda ilova xotira tugab, yopiladi
Ekranda bir vaqtda faqat 8-10 ta karta ko'rinadi. Qolgan 1990 tasini chizish — isrof. FlatList aynan shuni hal qiladi.
FlatList asoslari
import { FlatList, View, Text, StyleSheet } from 'react-native';
type Mahsulot = { id: number; nom: string; narx: number };
const mahsulotlar: Mahsulot[] = Array.from({ length: 2000 }, (_, i) => ({
id: i + 1,
nom: `Mahsulot ${i + 1}`,
narx: (i + 1) * 15000,
}));
export default function Katalog() {
return (
<FlatList
data={mahsulotlar}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<View style={styles.band}>
<Text style={styles.nom}>{item.nom}</Text>
<Text style={styles.narx}>{item.narx.toLocaleString()} so'm</Text>
</View>
)}
contentContainerStyle={{ padding: 16, gap: 8 }}
/>
);
}
const styles = StyleSheet.create({
band: { backgroundColor: 'white', padding: 16, borderRadius: 10 },
nom: { fontSize: 16, fontWeight: '600' },
narx: { color: '#0284c7', marginTop: 4 },
});
| Xususiyat | Ma'nosi |
|---|---|
data |
Ma'lumotlar massivi |
renderItem |
Bitta elementni chizish funksiyasi; { item, index } oladi |
keyExtractor |
Har bir elementning noyob kaliti — string |
FlatList faqat ekrandagi va uning atrofidagi elementlarni chizadi. Scroll qilganingizda — chiqib ketganlarini o'chiradi, kirayotganlarini yaratadi. 2000 ham, 200 000 ham — silliq. Bu virtualizatsiya.
renderItem ni alohida komponentga
import { memo } from 'react';
const MahsulotBand = memo(function MahsulotBand({ item }: { item: Mahsulot }) {
return (
<View style={styles.band}>
<Text style={styles.nom}>{item.nom}</Text>
<Text style={styles.narx}>{item.narx.toLocaleString()} so'm</Text>
</View>
);
});
<FlatList
data={mahsulotlar}
keyExtractor={(m) => String(m.id)}
renderItem={({ item }) => <MahsulotBand item={item} />}
/>
memo — element props o'zgarmasa qayta chizilmaydi. Uzun ro'yxatlarda sezilarli tezlik.
Ro'yxat qismlari
<FlatList
data={mahsulotlar}
renderItem={...}
ListHeaderComponent={<Text style={styles.sarlavha}>Barcha mahsulotlar</Text>}
ListFooterComponent={yuklanmoqda ? <ActivityIndicator style={{ margin: 16 }} /> : null}
ListEmptyComponent={<Text style={styles.bosh}>Hech narsa topilmadi</Text>}
ItemSeparatorComponent={() => <View style={{ height: StyleSheet.hairlineWidth, backgroundColor: '#e2e8f0' }} />}
/>
ListHeaderComponent— ro'yxat bilan birga aylanadigan sarlavha (banner, qidiruv, filtrlar). ScrollView ichiga FlatList qo'yish o'rniga — shu (8-dars)ListEmptyComponent—databo'sh bo'lgandaItemSeparatorComponent— elementlar orasida (birinchisidan oldin va oxirgisidan keyin emas)
Pastga tortib yangilash
const [yangilanmoqda, setYangilanmoqda] = useState(false);
async function yangila() {
setYangilanmoqda(true);
await mahsulotlarniYukla();
setYangilanmoqda(false);
}
<FlatList
data={mahsulotlar}
renderItem={...}
refreshing={yangilanmoqda}
onRefresh={yangila}
/>
Ikki xususiyat — va har bir mobil foydalanuvchiga tanish "pull-to-refresh" tayyor.
Ustunlar (grid)
<FlatList
data={mahsulotlar}
numColumns={2}
key="grid-2" // numColumns o'zgarsa — key ham
columnWrapperStyle={{ gap: 12 }}
contentContainerStyle={{ padding: 16, gap: 12 }}
renderItem={({ item }) => (
<View style={{ flex: 1, backgroundColor: 'white', borderRadius: 12, padding: 12 }}>
<Image source={{ uri: item.rasm }} style={{ width: '100%', aspectRatio: 1, borderRadius: 8 }} />
<Text numberOfLines={2}>{item.nom}</Text>
</View>
)}
/>
flex: 1— har bir karta ustun kengligini teng egallaydicolumnWrapperStyle— har bir qator uchun stil (ustunlar orasidagigap)- Toq sonli elementlarda oxirgi karta butun qatorni egallab qoladi — buni oldini olish uchun
maxWidth: '48%'yoki bo'sh "soxta" element
Gorizontal ro'yxat
<FlatList
horizontal
data={toifalar}
keyExtractor={(t) => t.id}
renderItem={({ item }) => <ToifaChip toifa={item} />}
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ paddingHorizontal: 16, gap: 8 }}
/>
Bosh sahifadagi "Ommabop", "Yangi kelganlar" qatorlari. Vertikal FlatList ning ListHeaderComponent i ichida gorizontal FlatList — muammo emas (yo'nalishlar har xil).
Tezlik sozlamalari
<FlatList
data={...}
renderItem={...}
initialNumToRender={10} // birinchi chizishda nechta
maxToRenderPerBatch={10}
windowSize={7} // ekrandan nechta "ekran" oldin/keyin xotirada
removeClippedSubviews // Android: ekrandan tashqarisini ajratish
getItemLayout={(_, index) => ({ length: 80, offset: 80 * index, index })}
/>
getItemLayout — barcha elementlar bir xil balandlikda bo'lsa (masalan, 80). FlatList har birini o'lchamasdan pozitsiyani biladi — scrollToIndex va tez scroll ancha silliq.
FlashList — yanada tez
Juda uzun va murakkab ro'yxatlar uchun Shopify ning FlashList kutubxonasi:
npx expo install @shopify/flash-list
import { FlashList } from '@shopify/flash-list';
<FlashList data={mahsulotlar} renderItem={...} />
FlatList bilan deyarli bir xil API, lekin elementlarni yo'q qilish o'rniga qayta ishlatadi (recycling) — ko'p hollarda sezilarli tezroq.
Kodda scroll
const ref = useRef<FlatList<Mahsulot>>(null);
ref.current?.scrollToOffset({ offset: 0, animated: true }); // tepaga
ref.current?.scrollToIndex({ index: 50, animated: true }); // 50-elementga
Tab ikonkasi ikkinchi marta bosilganda ro'yxat tepasiga qaytish — klassik UX.
Nima uchun shunday?
Nima uchun keyExtractor majburiy va u nima uchun string bo'lishi kerak?
FlatList elementlarni yaratib-o'chirib turadi. Kalit — React ga "bu element o'shami?" degan savolga javob beradi. Kalit sifatida indeks ishlatilsa va ro'yxat boshiga yangi element qo'shilsa — barcha indekslar siljiydi, React esa har bir elementni "o'zgargan" deb qayta chizadi (yoki yomonroq — noto'g'ri elementning holatini saqlab qoladi: belgilangan checkbox boshqa qatorga "sakraydi"). Noyob id asosidagi kalit bu muammolarni yo'q qiladi. String bo'lishi — React Native ning ichki talabi.
Xulosa
Eslab qoling:
FlatList— virtualizatsiya: faqat ko'rinadiganlar chiziladidata,renderItem,keyExtractor(noyobid, string) — majburiy uchlikrenderItem— alohidamemokomponentListHeaderComponent,ListFooterComponent,ListEmptyComponent,ItemSeparatorComponentrefreshing+onRefresh— pull-to-refreshnumColumns— grid;horizontal— gorizontal qator- Bir xil balandlik —
getItemLayout; juda katta ro'yxatlar — FlashList
Keyingi dars
20-dars: SectionList va cheksiz scroll (onEndReached)