Hubert
15 min
30 kwietnia, 2025

Renderowanie list w React Native

Jak wyświetlać setki elementów w aplikacji mobilnej bez utraty płynności? W świecie React Native listy to coś więcej niż tylko przewijanie danych — to wydajność, kontrola i doświadczenie użytkownika. Poznaj nowoczesne podejście do renderowania list i sprawdź, dlaczego FlashList staje się nowym standardem.

Czytaj więcej
Renderowanie list w React Native

Renderowanie list w aplikacjach mobilnych to jedno z kluczowych zagadnień, wpływających na wydajność i jakość doświadczenia użytkownika. W ekosystemie React Native dostępnych jest kilka komponentów umożliwiających efektywne wyświetlanie dużych zbiorów danych. Każde rozwiązanie różni się podejściem do zarządzania pamięcią, strategią renderowania oraz optymalizacją wydajności.

Artykuł przedstawia najpopularniejsze sposoby renderowania list w React Native, omawiając pięć kluczowych komponentów: ScrollView, FlatList, SectionList, VirtualizedList oraz FlashList. Szczególny nacisk położono na FlashList — nowoczesne narzędzie stworzone przez Shopify, zaprojektowane specjalnie z myślą o płynnej obsłudze bardzo dużych zbiorów danych. Celem tekstu jest przedstawienie charakterystyki poszczególnych rozwiązań oraz pomoc w wyborze najlepszego komponentu w zależności od potrzeb aplikacji.

1. ScrollView

ScrollView to podstawowy komponent w React Native służący do wyświetlania przewijalnych widoków, w których cała zawartość jest renderowana jednocześnie w pamięci urządzenia. Idealnie sprawdza się w przypadku niewielkich ilości danych lub statycznych układów, gdzie pełne załadowanie całego kontentu nie wpływa negatywnie na wydajność.

W odróżnieniu od bardziej zaawansowanych komponentów, takich jak FlatList czy FlashList, ScrollView nie korzysta z wirtualizacji — każdy element jest w pełni wyrenderowany, niezależnie od tego, czy jest aktualnie widoczny na ekranie.

Charakterystyka komponentu ScrollView

  • brak wirtualizacji: Wszystkie elementy są ładowane i przechowywane w pamięci od razu.
  • potencjalne problemy z wydajnością: Przy dużych zbiorach danych może dochodzić do zwiększonego zużycia pamięci (Out Of Memory) oraz spowolnienia działania aplikacji.
  • łatwość implementacji: ScrollView jest wyjątkowo prosty w użyciu i świetnie sprawdza się w przypadku krótkich list, formularzy, statycznych ekranów lub w sytuacjach, gdy lista ma z góry określoną, niewielką liczbę elementów.
  • obsługa przewijania w pionie lub poziomie: Domyślnie przewija w pionie (vertical), ale można łatwo przełączyć na przewijanie poziome (horizontal={true}).
  • wsparcie dla różnych efektów przewijania: Takich jak pagingEnabled, showsVerticalScrollIndicator, bounces itp.

Kiedy unikać ScrollView?

ScrollView nie jest najlepszym wyborem w sytuacjach, gdy dane są dynamicznie pobierane z API i ich liczba nie jest z góry określona. Również wtedy, gdy istnieje ryzyko, że lista będzie zawierać setki lub tysiące elementów, użycie ScrollView może prowadzić do poważnych problemów z wydajnością i zużyciem pamięci. W przypadkach, gdy dla aplikacji kluczowe jest zachowanie płynności działania oraz optymalne gospodarowanie zasobami urządzenia, znacznie lepszym rozwiązaniem będzie wykorzystanie komponentów opartych na wirtualizacji, takich jak FlatList lub FlashList.

Przykład kodu z listą ScrollView:

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

const App = () => (
  <ScrollView>
    {[...Array(20)].map((_, index) => (
      <View key={index} style={{ padding: 20, backgroundColor: '#e0e0e0', marginBottom: 10 }}>
        <Text>Item {index + 1}</Text>
      </View>
    ))}
  </ScrollView>
);

W powyższym przykładzie ScrollView renderuje 20 elementów od razu, zapewniając prosty i szybki sposób na przewijalną zawartość.

Szukasz solidnego wsparcia w projektach mobilnych?
Szukasz solidnego wsparcia w projektach mobilnych?
Szukasz solidnego wsparcia w projektach mobilnych?
Napisz do nas!

2. FlatList

FlatList to jeden z najczęściej używanych komponentów do renderowania list w React Native. Został zaprojektowany z myślą o efektywnym wyświetlaniu dużych zbiorów danych, bez konieczności ładowania wszystkich elementów naraz. W przeciwieństwie do ScrollView, FlatList korzysta z mechanizmu wirtualizacji — renderuje tylko te elementy, które są aktualnie widoczne na ekranie, oraz niewielką liczbę dodatkowych elementów buforowych. Dzięki temu znacząco ogranicza zużycie pamięci i poprawia płynność działania aplikacji.

FlatList działa najlepiej wtedy, gdy dane są jednorodne i nie wymagają specjalnego grupowania. Pozwala także na łatwe zarządzanie nagłówkami, stopkami, separatorami pomiędzy elementami oraz obsługą gestów typu „pull-to-refresh” czy nieskończonego przewijania (infinite scroll).

Charakterystyka FlatList

FlatList automatycznie zarządza procesem tworzenia i niszczenia widoków, dbając o to, aby w pamięci znajdowały się jedynie te elementy, które są rzeczywiście potrzebne w danym momencie. Kluczowe właściwości, takie jak initialNumToRender, maxToRenderPerBatch czy windowSize, umożliwiają dostosowanie liczby renderowanych elementów do specyfiki aplikacji i oczekiwanej wydajności.

Jedną z największych zalet FlatList jest prostota implementacji przy jednoczesnym zachowaniu dobrej wydajności nawet przy dużych zbiorach danych. Jednak przy ekstremalnie dużych listach, liczących dziesiątki tysięcy elementów, komponent ten może wykazywać pewne ograniczenia w płynności działania, szczególnie na starszych lub słabszych urządzeniach. FlatList umożliwia także łatwe tworzenie list wielokolumnowych poprzez ustawienie właściwości numColumns, co czyni go elastycznym narzędziem nie tylko dla standardowych układów pionowych.

Warto pamiętać, że dla każdej pozycji w FlatList konieczne jest zdefiniowanie unikalnego klucza (keyExtractor), aby zapewnić sprawne śledzenie zmian w danych i optymalizację procesu renderowania.

Przykład kodu:

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

const App = () => {
  const data = [...Array(100)].map((_, i) => `Item ${i + 1}`);

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => (
        <View style={{ padding: 20, backgroundColor: '#f0f0f0', marginVertical: 5 }}>
          <Text>{item}</Text>
        </View>
      )}
      keyExtractor={(item, index) => index.toString()}
      initialNumToRender={10}
    />
  );
};

W powyższym przykładzie FlatList dynamicznie renderuje tylko część elementów, zaczynając od początkowych 10, a następnie stopniowo ładuje kolejne w miarę przewijania listy. Dzięki temu nawet przy stu elementach pamięć urządzenia nie jest nadmiernie obciążona, a użytkownik doświadcza płynnego przewijania.

3. SectionList

SectionList to zaawansowany komponent React Native, który rozszerza możliwości FlatList o funkcję grupowania danych w sekcje. Idealnie sprawdza się w sytuacjach, gdy lista danych wymaga wyraźnego podziału na kategorie lub grupy, takich jak lista kontaktów posortowana alfabetycznie, katalog produktów według kategorii czy harmonogram wydarzeń podzielony na dni.

Pod względem działania SectionList opiera się na tym samym mechanizmie wirtualizacji, co FlatList, co oznacza, że renderuje jedynie widoczne elementy oraz niewielki bufor poza ekranem. Pozwala to na zachowanie wysokiej wydajności nawet przy dużych ilościach danych, przy jednoczesnym zapewnieniu bardziej rozbudowanej struktury listy.

Charakterystyka komponentu SectionList

SectionList przyjmuje dane w specjalnym formacie — jako tablicę obiektów, z których każdy reprezentuje osobną sekcję i zawiera własny nagłówek oraz zestaw elementów (data). Dzięki temu możliwe jest przypisanie indywidualnych nagłówków dla każdej grupy danych, co znacznie poprawia czytelność i organizację treści w aplikacji.

Komponent ten obsługuje zarówno niestandardowe renderowanie nagłówków (renderSectionHeader), jak i poszczególnych elementów (renderItem). Dodatkowo pozwala na definiowanie separatorów pomiędzy sekcjami, stopki całej listy (ListFooterComponent) oraz możliwość odświeżania danych przez przeciągnięcie (refreshControl).

Warto pamiętać, że podobnie jak w przypadku FlatList, dla zachowania optymalnej wydajności, niezbędne jest poprawne zdefiniowanie kluczy dla poszczególnych elementów (keyExtractor).

SectionList, choć bardzo funkcjonalny, najlepiej sprawdza się w aplikacjach, gdzie organizacja danych w grupy jest logicznie uzasadniona i znacząco wpływa na komfort użytkowania.

Przykład kodu:

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

const App = () => {
  const sections = [
    { title: 'A', data: ['Apple', 'Avocado'] },
    { title: 'B', data: ['Banana', 'Blueberry', 'Blackberry'] },
    { title: 'C', data: ['Cherry', 'Coconut'] },
  ];

  return (
    <SectionList
      sections={sections}
      renderItem={({ item }) => (
        <View style={{ padding: 15, backgroundColor: '#f9f9f9', marginVertical: 4 }}>
          <Text>{item}</Text>
        </View>
      )}
      renderSectionHeader={({ section: { title } }) => (
        <View style={{ backgroundColor: '#ddd', padding: 10 }}>
          <Text style={{ fontWeight: 'bold' }}>{title}</Text>
        </View>
      )}
      keyExtractor={(item, index) => item + index}
    />
  );
};

W tym przykładzie SectionList renderuje trzy sekcje z odpowiednimi nagłówkami, wyświetlając w sposób przejrzysty pogrupowane dane. Taki układ jest szczególnie użyteczny w aplikacjach, gdzie użytkownik oczekuje łatwej nawigacji po większej liczbie kategorii lub grupowanych informacji.

4. VirtualizedList

VirtualizedList to komponent niskopoziomowy w React Native, będący fundamentem, na którym zbudowane zostały bardziej popularne komponenty takie jak FlatList i SectionList. Zapewnia pełną kontrolę nad mechanizmem renderowania listy, umożliwiając deweloperowi zarządzanie tym, które elementy mają być aktualnie widoczne, a które powinny być przechowywane w pamięci. Jest to rozwiązanie przeznaczone głównie dla zaawansowanych scenariuszy, w których standardowe komponenty nie oferują wystarczającej elastyczności.

VirtualizedList nie przyjmuje gotowej tablicy danych, jak FlatList, lecz wymaga jawnego określenia sposobu pobierania elementów (getItem) oraz liczby elementów w zbiorze (getItemCount). Dzięki temu można w sposób bardziej wydajny zarządzać pamięcią i optymalizować zachowanie listy przy niestandardowych źródłach danych, takich jak strumienie, bazy lokalne czy dynamiczne generatory.

Charakterystyka VirtualizedList

VirtualizedList zapewnia bardzo wysoki poziom kontroli nad procesem renderowania, co czyni go odpowiednim wyborem w sytuacjach wymagających niestandardowych struktur danych lub nietypowych sposobów przetwarzania zawartości listy.

Jednocześnie korzystanie z VirtualizedList wiąże się z większą odpowiedzialnością programisty. Wymaga ono ręcznego zaimplementowania funkcji obsługujących dane oraz odpowiedniego zarządzania kluczami, aby zapewnić płynność działania i uniknąć problemów z nieefektywnym renderowaniem.

Komponent ten obsługuje wszystkie funkcje typowe dla wirtualizowanych list: renderowanie tylko widocznych elementów, możliwość ustawienia liczby elementów początkowych (initialNumToRender), kontrolę okna renderowania (windowSize) oraz wsparcie dla funkcji odświeżania (onRefresh) czy ładowania kolejnych danych przy przewijaniu (onEndReached).

VirtualizedList z zasady nie jest rekomendowany jako pierwszy wybór dla większości projektów — jeśli potrzeby aplikacji są standardowe, bardziej odpowiednie będą FlatList lub FlashList. Jednak w przypadkach bardzo specyficznych struktur danych, VirtualizedList pozostaje niezwykle potężnym narzędziem.

Przykład kodu:

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

const App = () => {
  const data = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`);

  const getItem = (data, index) => data[index];
  const getItemCount = (data) => data.length;

  return (
    <VirtualizedList
      data={data}
      initialNumToRender={10}
      renderItem={({ item }) => (
        <View style={{ padding: 20, backgroundColor: '#e0f7fa', marginVertical: 5 }}>
          <Text>{item}</Text>
        </View>
      )}
      keyExtractor={(item, index) => index.toString()}
      getItem={getItem}
      getItemCount={getItemCount}
    />
  );
};

W powyższym przykładzie VirtualizedList renderuje elementy dynamicznie, używając własnych funkcji getItem i getItemCount. Choć kod jest nieco bardziej rozbudowany niż w przypadku FlatList, daje pełną kontrolę nad tym, jak dane są pobierane i przetwarzane w trakcie działania aplikacji.

5. FlashList

FlashList to nowoczesny komponent listy stworzony przez Shopify, zaprojektowany specjalnie z myślą o maksymalnej wydajności i skalowalności w aplikacjach mobilnych. Stanowi odpowiedź na ograniczenia tradycyjnych rozwiązań, takich jak FlatList, które przy bardzo dużych zbiorach danych mogą tracić płynność działania. Dzięki FlashList możliwe jest budowanie list zawierających nawet setki tysięcy elementów bez zauważalnych spadków wydajności — i to przy minimalnym nakładzie konfiguracji.

W odróżnieniu od wcześniejszych komponentów, FlashList wprowadza mechanizmy znane z natywnych rozwiązań takich jak RecyclerView (Android) czy UITableView (iOS), wykorzystując recykling widoków, precyzyjne szacowanie rozmiarów elementów i inteligentne zarządzanie pamięcią. Wszystko to przekłada się na znacznie mniejsze zużycie zasobów i bardziej płynne przewijanie.

FlashList został zaprojektowany tak, aby był jak najłatwiejszy w użyciu. Jego API przypomina FlatList, dzięki czemu migracja istniejących projektów może być szybka i bezproblemowa.

Charakterystyka FlashList

FlashList wyróżnia się kilkoma kluczowymi cechami, które czynią go obecnie jednym z najlepszych narzędzi do renderowania dużych list w React Native:

Przede wszystkim implementuje recykling widoków, czyli ponowne używanie tych samych komponentów do renderowania kolejnych elementów listy. Dzięki temu liczba widoków istniejących w pamięci jest drastycznie ograniczona w porównaniu do FlatList, gdzie każdy element posiada osobny komponent.

Kolejną istotną cechą jest wykorzystanie precyzyjnego szacowania rozmiarów elementów. Używając właściwości estimatedItemSize, FlashList optymalizuje układ listy jeszcze przed rzeczywistym renderowaniem, co eliminuje wiele kosztownych operacji przeliczania rozmiarów i pozwala na osiągnięcie wyjątkowej płynności podczas przewijania.

FlashList zapewnia także wsparcie dla funkcji takich jak nagłówki, stopki, separator elementów, obsługa sekcji (za pomocą FlashList.SectionList), paginacja oraz pull-to-refresh, co czyni go rozwiązaniem kompletnym i gotowym do użycia w praktycznie każdym scenariuszu.

Warto podkreślić, że mimo wszystkich zaawansowanych funkcji, konfiguracja FlashList pozostaje niezwykle prosta. W większości przypadków wystarczy jedynie podać dane, funkcję renderItem oraz wartość estimatedItemSize.

Dlaczego warto wybrać FlashList?

FlashList jest rekomendowany wszędzie tam, gdzie liczba elementów jest wysoka lub dane są dynamiczne i zmieniają się w czasie. Sprawdza się znakomicie zarówno w aplikacjach e-commerce (katalogi produktów), aplikacjach społecznościowych (feedy), jak i w systemach zarządzania treścią (CMS, CRM).

W porównaniu do FlatList, FlashList może oferować nawet kilkukrotnie większą płynność przewijania i nawet 10-krotnie niższe zużycie pamięci przy bardzo dużych listach.

FlashList to komponent przyszłości, który pozwala aplikacjom React Native działać na poziomie wydajności zbliżonym do natywnych aplikacji.

Przykład kodu:

import { FlashList } from '@shopify/flash-list';
import { View, Text } from 'react-native';

const data = Array.from({ length: 1000 }, (_, i) => ({ id: i.toString(), title: `Item ${i + 1}` }));

const App = () => (
  <FlashList
    data={data}
    renderItem={({ item }) => (
      <View style={{ height: 70, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f0f0f0', marginVertical: 4 }}>
        <Text style={{ fontSize: 18 }}>{item.title}</Text>
      </View>
    )}
    keyExtractor={(item) => item.id}
    estimatedItemSize={70}
  />
);

Dodatkowe atuty FlashList

Oprócz standardowych funkcji, FlashList oferuje także adaptacyjne zarządzanie wydajnością. Komponent automatycznie dostosowuje liczbę utrzymywanych widoków do szybkości przewijania, rozdzielczości ekranu oraz możliwości urządzenia, zapewniając płynność bez konieczności ręcznego dostrajania parametrów takich jak windowSize czy maxToRenderPerBatch, które w przypadku FlatList często wymagały dodatkowej konfiguracji.

FlashList świetnie radzi sobie również z listami zawierającymi elementy o zmiennej lub nieregularnej wysokości. Dzięki funkcji overrideItemLayout programista może ręcznie podać wysokość konkretnego elementu, co umożliwia zachowanie wysokiej wydajności nawet w bardzo dynamicznych układach treści.

Jednym z kluczowych atutów jest także łatwa migracja. Ze względu na dużą zgodność API z FlatList, w większości przypadków migracja sprowadza się do zmiany importu oraz dodania właściwości estimatedItemSize. To czyni FlashList atrakcyjnym rozwiązaniem zarówno dla nowych projektów, jak i istniejących aplikacji wymagających optymalizacji wydajności.

Co więcej, FlashList obsługuje sekcje i grupowanie danych poprzez komponent FlashList.SectionList, umożliwiając tworzenie bardziej zaawansowanych i uporządkowanych struktur listy, bez kompromisów w zakresie wydajności.

Wreszcie, FlashList zapewnia bardziej przewidywalne i stabilne przewijanie nawet w aplikacjach o bardzo dynamicznym układzie danych. Dzięki lepszemu zarządzaniu rozmiarami elementów i zaawansowanej wirtualizacji użytkownicy mogą doświadczać idealnie płynnych animacji bez niepożądanych skoków czy opóźnień, które często występowały w starszych rozwiązaniach.

Podsumowanie

Renderowanie list w React Native to temat, który wymaga świadomego podejścia, zwłaszcza gdy aplikacja ma obsługiwać duże i dynamiczne zbiory danych. Każdy z omówionych komponentów — ScrollView, FlatList, SectionList, VirtualizedList i FlashList — ma swoje konkretne zastosowania i ograniczenia. ScrollView świetnie sprawdza się przy niewielkiej liczbie elementów, FlatList i SectionList oferują zbalansowaną wydajność przy typowych listach, a VirtualizedList zapewnia pełną kontrolę tam, gdzie potrzeba nietypowych rozwiązań. Największą uwagę warto jednak zwrócić na FlashList — komponent nowej generacji, który łączy prostotę z wyjątkową wydajnością. Dzięki recyklingowi widoków, adaptacyjnemu zarządzaniu pamięcią oraz wsparciu dla dużych i złożonych struktur danych, FlashList stanowi obecnie najlepszy wybór dla aplikacji, które muszą działać szybko, płynnie i niezawodnie — niezależnie od skali.

FAQ – Najczęściej zadawane pytania o listy w React Native

1. Czy FlashList działa z Expo?

Tak, FlashList działa w projektach opartych na Expo, ale wymaga dodania zewnętrznej paczki @shopify/flash-list. W starszych wersjach Expo może być konieczne użycie trybu „bare workflow”.

2. Jak testować wydajność list w React Native?

Wydajność list najlepiej mierzyć za pomocą narzędzi takich jak Flipper, React DevTools oraz Profile w Android Studio. Warto monitorować czas renderowania oraz zużycie pamięci w trakcie przewijania dużej liczby elementów.

3. Czy FlashList obsługuje listy poziome (horizontal)?

Tak, FlashList wspiera listy przewijane poziomo — wystarczy ustawić horizontal={true}, podobnie jak w FlatList. Dodatkowo można stosować estimatedItemSize w szerokości zamiast wysokości.

4. Jak FlashList radzi sobie z dynamicznie aktualizowanymi danymi?

FlashList świetnie obsługuje aktualizacje danych dzięki optymalizacji procesu różnicowania (diffing). Dobrze reaguje na zmiany, ale dla najlepszych efektów warto stosować stabilne klucze (keyExtractor) i unikać bezpośredniej mutacji danych.

5. Czy FlashList wspiera animacje podczas przewijania?

Tak, FlashList współpracuje z bibliotekami takimi jak Reanimated czy React Native Gesture Handler, co pozwala dodawać animacje elementów w trakcie przewijania, np. efekty paralaksy lub fade-in bez dużego wpływu na wydajność.

Powiązane artykuły
Zobacz wszystkie
Odkryj więcej tematów