FlatList — podstawowy komponent React Native do wyświetlania wydajnych list z wirtualizacją elementów. W przeciwieństwie do ScrollView, FlatList renderuje tylko widoczne elementy ekranu, oszczędzając pamięć i procesor. Komponent obsługuje przewijanie poziome i pionowe, pull-to-refresh oraz nieskończone ładowanie. Więcej o architekturze list przeczytasz w dokumentacji Meta.
Najważniejsze
FlatList — komponent React Native implementujący wirtualizowaną listę z wydajnym renderowaniem dużych ilości danych. Komponent jest zbudowany na bazie VirtualizedList i udostępnia deklaratywne API do tworzenia płaskich list o dowolnym stopniu złożoności.
FlatList pojawił się w React Native 0.43 jako zamiennik przestarzałego ListView. Według danych Meta (2026), FlatList jest używany w 85% aplikacji React Native pracujących z listami. Komponent obsługuje wszystkie popularne scenariusze: kontakty, kanały informacyjne, katalogi produktów, czaty.
Przed pojawieniem się FlatList programiści używali ListView, który wymagał ręcznej konfiguracji ponownego wykorzystania komórek. FlatList zautomatyzował ten proces, wprowadzając renderowanie okienkowe na wzór RecyclerView w Androidzie (2014) i UICollectionView w iOS (2012). W nowoczesnych projektach FlatList jest standardem de facto dla wszystkich list.
Wirtualizacja FlatList — mechanizm, w którym komponent renderuje tylko te elementy, które znajdują się w widocznym obszarze ekranu, plus niewielki bufor po każdej stronie. Pozostałe elementy nie są tworzone w DOM, co oszczędza pamięć i przyspiesza renderowanie.
Podczas przewijania FlatList ponownie wykorzystuje już utworzone widoki View, zastępując w nich dane. Zapobiega to tworzeniu tysięcy widoków dla listy 10 000 elementów. Domyślny rozmiar bufora to 10 elementów powyżej i poniżej widocznego obszaru, ale można go skonfigurować za pomocą windowSize.
| Parametr | Domyślnie | Opis |
|---|---|---|
| windowSize | 21 | Liczba stron do renderowania (1 strona = wysokość ekranu) |
| initialNumToRender | 10 | Liczba elementów przy pierwszym renderowaniu |
| maxToRenderPerBatch | 10 | Maksymalna liczba elementów renderowanych w jednej partii |
| removeClippedSubviews | false | Usuwanie widoków poza ekranem z hierarchii |
Optymalna konfiguracja tych parametrów pozwala zrównoważyć płynność przewijania i zużycie pamięci. W przypadku list z dużymi elementami zaleca się zmniejszenie windowSize do 5-7.
FlatList API obejmuje zestaw właściwości do konfiguracji wyglądu i zachowania listy. Dwie obowiązkowe właściwości to data (tablica danych) i renderItem (funkcja renderowania elementu). keyExtractor zwiększa wydajność, dostarczając unikalny klucz dla każdego elementu.
import React from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
const App = () => {
const data = Array.from({ length: 100 }, (_, i) => ({
id: i.toString(),
title: `Item #${i + 1}`,
}));
return (
<FlatList
data={data}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
</View>
)}
keyExtractor={item => item.id}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
);
};ItemSeparatorComponent dodaje separator między elementami, ListHeaderComponent i ListFooterComponent — nagłówek i stopkę listy. Umożliwia to tworzenie złożonych układów bez dodatkowego opakowania.
const styles = StyleSheet.create({
item: {
padding: 16,
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
},
separator: {
height: 1,
backgroundColor: '#ccc',
},
});Optymalizacja FlatList jest krytycznie ważna dla aplikacji z setkami i tysiącami elementów. Bez prawidłowej konfiguracji lista może działać wolno podczas przewijania, zużywać nadmierną pamięć i powodować awarie na słabszych urządzeniach.
Pierwszą zasadą jest używanie keyExtractor z unikalnymi i stabilnymi identyfikatorami. Indeksy jako klucze prowadzą do nieprawidłowego ponownego wykorzystania komórek i błędów stanu. Drugą — owijanie renderItem w useCallback i używanie React.memo dla komponentu elementu.
Jeśli wszystkie elementy mają tę samą wysokość, getItemLayout pozwala FlatList obliczać pozycję przewijania bez mierzenia komponentów. Daje to znaczący wzrost wydajności, szczególnie podczas przewijania do określonego indeksu.
const ITEM_HEIGHT = 80;
const getItemLayout = (data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
});
<FlatList
data={data}
getItemLayout={getItemLayout}
renderItem={renderItem}
/FlatList>useMemo dla danych zapobiega zbędnym przerenderowaniom. Jeśli dane pochodzą z API, przetwórz je raz i zapisz w pamięci podręcznej. Używaj React.memo dla komponentu elementu, aby uniknąć renderowania niezmienionych elementów.
Poziomy FlatList tworzy się przez dodanie właściwości horizontal={true}. Lista zmienia kierunek przewijania na oś X, co jest wygodne dla karuzel produktów, galerii obrazów i poziomych menu.
W trybie poziomym ważne jest prawidłowe skonfigurowanie snapToInterval i snapToAlignment dla krokowego przewijania, jak w natywnych karuzelach. Komponent automatycznie obsługuje pęd i puszczanie palca, zatrzymując się na najbliższym elemencie.
<FlatList
horizontal
data={images}
renderItem={renderItem}
keyExtractor={item => item.id}
showsHorizontalScrollIndicator={false}
snapToInterval={CARD_WIDTH + GAP}
snapToAlignment="start"
decelerationRate="fast"
pagingEnabled
onViewableItemsChanged={onViewableItemsChanged}
/>onViewableItemsChanged — callback wywoływany przy zmianie widocznych elementów. Używany do analityki, leniwego ładowania obrazów i aktywacji wideo tylko dla widocznych kart.
Pull-to-refresh w FlatList implementuje się za pomocą właściwości refreshing i onRefresh, działających w parze ze stanem ładowania. Przy przeciągnięciu listy w dół wywoływany jest onRefresh, a flaga refreshing blokuje ponowne wywołania.
Nieskończone ładowanie (infinite scroll) konfiguruje się przez onEndReached — callback wyzwalany przy zbliżaniu się do końca listy. onEndReachedThreshold określa, ile elementów przed końcem wyzwala zdarzenie. Do paginacji zwykle stosuje się podejście cursor-based.
const ListWithPagination = () => {
const [data, setData] = React.useState([]);
const [page, setPage] = React.useState(1);
const [refreshing, setRefreshing] = React.useState(false);
const loadMore = React.useCallback(async () => {
const newData = await fetchPage(page);
setData(prev => [...prev, ...newData]);
setPage(p => p + 1);
}, [page]);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
refreshing={refreshing}
onRefresh={loadMore}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
);
};Ważne: onEndReached może być wywoływany wielokrotnie. Dodaj flagę isLoading, aby blokować powtarzające się żądania, dopóki poprzednie się nie zakończy. Użyj ActivityIndicator w ListFooterComponent do wskazania ładowania.
Często zadawane pytania
FlatList używa wirtualizacji — renderuje tylko widoczne elementy, co oszczędza pamięć przy dużych danych. ScrollView renderuje wszystkie elementy potomne od razu, nadaje się tylko do małych list do 20-30 elementów. FlatList jest optymalny dla 100+ elementów.
Migotanie występuje przy zmianie referencji tablicy data. Użyj extraData, przekazując tam zależność, lub owijaj renderItem w React.memo. Do pełnej kontroli stosuj useMemo do stabilizacji referencji danych.
FlatList nie jest przeznaczony do zagnieżdżania w ScrollView z powodu konfliktu gestów. Rozwiązania: użyj FlatList z nestedScrollEnabled (Android), SectionList dla sekcji lub wynieś zewnętrzne przewijanie do FlatList przez ListHeaderComponent.
Użyj Animated API wewnątrz renderItem z opóźnieniem na podstawie indeksu. Podczas przewijania stosuj onViewableItemsChanged do wyzwalania animacji. Biblioteki react-native-reanimated i react-native-lottie ułatwiają tworzenie złożonych animacji pojawiania się.
VirtualizedList — podstawowy komponent wirtualizacji, na którym zbudowane są FlatList i SectionList. FlatList to otoczka VirtualizedList z uproszczonym API dla płaskich list. VirtualizedList zapewnia bardziej niskopoziomową kontrolę, ale rzadko jest używany bezpośrednio.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również