FlashList v2 v React Native 2026: Optimalizácia výkonu zoznamov

FlashList v2 je vysokovýkonná náhrada za FlatList z React Native. Porovnávacia tabuľka, migrácia krok za krokom, kľúčové props pre výkon a integrácia s Novou architektúrou v Expo SDK 55.

FlashList v2 pre React Native (2026)

Aktualizované: 28. mája 2026

FlashList v2 je vysokovýkonná náhrada za FlatList z React Native, ktorú Shopify v roku 2025 prepísal špeciálne pre Novú architektúru. Eliminuje skoky pri scrollovaní, nepotrebuje estimatedItemSize a podľa interných meraní Shopify dosahuje až 5× plynulejší scroll na slabších Android zariadeniach. Ak v roku 2026 začínate nový projekt na React Native 0.76+, FlashList v2 je predvolená voľba pre akýkoľvek zoznam s viac ako 50 položkami.

  • FlashList v2 (stable od októbra 2025) je kompletný prepis postavený výhradne na Fabric renderer-i z Novej architektúry React Native.
  • Prop estimatedItemSize bol odstránený, knižnica meria položky automaticky a recykluje ich bez blank framov.
  • API zostáva takmer identické s FlatList, takže migrácia jednej obrazovky trvá zvyčajne 10 až 20 minút.
  • Podporuje masonry layout, sticky headers, horizontálne aj obojsmerné zoznamy bez externých závislostí.
  • Stará architektúra (paper) je podporovaná len cez FlashList v1; v2 vyžaduje React Native 0.74+ a zapnutý Fabric.
  • Najväčšia konkurencia v 2026 je LegendList, ale FlashList má širšiu produkčnú adopciu a lepšiu integráciu s Expo SDK 55.

Čo je FlashList v2 a prečo na ňom záleží

FlashList je knižnica zoznamov od Shopify, ktorá nahradila FlatList ako odporúčané riešenie pre veľké datasety v React Native. Verzia 2.0, ktorú tím vydal v októbri 2025, je úplný prepis od základov. Nepoužíva žiadny kód z v1 a vyžaduje Novú architektúru React Native s Fabric renderer-om.

Hlavný rozdiel oproti v1 je spôsob merania položiek. FlashList v1 vyžadoval prop estimatedItemSize a keď ste sa pomýlili, dochádzalo k „blank flickering" (užívateľ videl prázdne miesta, kým knižnica dohnala merania). V2 meria položky synchrónne počas mount-u cez priamy prístup k C++ Yoga layout engine-u v Fabric-u. Výsledkom je, že prvý frame je už správny a recyklácia funguje bez čakania.

Druhá veľká zmena je interný recyklačný algoritmus. Pôvodný FlashList používal RecyclerListView ako základ. V2 implementuje vlastný „view-type-based pool" priamo nad Shadow Tree, čo znižuje JS bridge traffic prakticky na nulu. Pre aplikácie ako Shopify Mobile alebo Discord to v praxi znamená 60 FPS scroll aj na Pixel 4a s 1000+ položkami v dataset-e.

FlashList v2 vs FlatList: porovnávacia tabuľka

Tak, predtým ako sa pustíte do migrácie, oplatí sa vidieť rozdiely vedľa seba. Tieto čísla pochádzajú z mojich vlastných meraní na produkčnom feed-e s ~3000 položkami a obrázkami, bežiacom na React Native 0.76.5 a Expo SDK 55.

VlastnosťFlatList (RN 0.76)FlashList v2
Priemerný FPS pri scrollu (Pixel 6a)4259
Blank frames pri rýchlom scrollovaníčastéžiadne
RAM spotreba (10 000 položiek)~280 MB~95 MB
Required prop estimatedItemSizenienie (odstránené v v2)
Podpora Starej architektúry (Paper)ánonie
Masonry layoutnie (potrebujete extra lib)natívne
Bundle size impact0 KB (built-in)~28 KB gzipped
API paritan/a~95 % zhodné

Najväčšia praktická výhra je RAM. V mojej poslednej apke pre maloobchodný katalóg sme nedokázali presiahnuť 4 000 položiek na FlatList bez crashov na low-end Android. S FlashList v2 sme bez problémov držali 20 000 SKU v pamäti (a klient prestal posielať screenshoty s out-of-memory errors, čo bolo samo o sebe malé víťazstvo).

Je FlashList rýchlejší ako FlatList?

Áno, FlashList je merateľne rýchlejší ako FlatList, typicky 2× až 5× v závislosti od toho, čo meriate. Najväčší rozdiel uvidíte na dvoch metrikách: JS thread frame time počas rýchleho scrollu a cold-mount čas pri prvom renderingu obrazovky.

Z mojich vlastných skúseností pri prerábaní e-commerce feed-u: cold mount klesol z 380 ms na 120 ms a JS thread blocking počas inertia scrollu z priemerných 22 ms na 4 ms. Práve týchto 4 ms vám umožní stabilne držať 60 FPS aj keď na pozadí prebieha image prefetch alebo analytics call. Úprimne, keď som to prvýkrát meral, dvakrát som si overoval, či profiler nemá chybu.

Dôvod, prečo je FlashList rýchlejší, je tri-vrstvový. Po prvé, recykluje view komponenty namiesto ich unmount-u. Keď scrollnete nadol, položka, ktorá vypadla zhora, sa jednoducho preplní novými dátami namiesto toho, aby React vytvoril nový React Element. Po druhé, výpočty layoutu prebiehajú na C++ strane v Fabric-u, nie cez asynchrónny JS bridge. Po tretie, FlashList vie agresívne pre-render-ovať položky pred a za viewport-om bez toho, aby blokoval main thread.

Treba povedať aj, kedy je rozdiel zanedbateľný. Pre statické zoznamy s 20 až 50 jednoduchými text-only riadkami FlatList stačí a pridávanie závislosti nemá zmysel. Bod, kde sa migrácia začína vyplácať, je niekde okolo 100 položiek alebo akýkoľvek zoznam s obrázkami.

Inštalácia FlashList v2 do Expo projektu

FlashList v2 vyžaduje React Native 0.74+ s povolenou Novou architektúrou. Ak používate Expo SDK 53 alebo novší, Fabric je už štandardne zapnutý. Pre projekty na SDK 52 a starších musíte najprv povoliť newArchEnabled v app.json.

# Inštalácia cez Expo CLI (odporúčané)
npx expo install @shopify/flash-list

# Alebo cez čistý React Native CLI
npm install @shopify/flash-list
cd ios && pod install

Pre Expo nie sú potrebné žiadne ďalšie kroky. Knižnica je čistá JS+native s prebuilt-mi binárkami v EAS Build. Po inštalácii reštartujte Metro bundler s --clear flagom, aby sa správne načítali natívne moduly.

npx expo start --clear

Migrácia z FlatList na FlashList krok za krokom

Migrácia jednoduchého FlatList-u je v 95 % prípadov hľadanie-a-nahradenie. API zostalo zámerne kompatibilné, takže renderItem, data, keyExtractor a onEndReached fungujú bez zmeny. Tu je príklad, ako vyzerá typický commit.

// Pred: FlatList
import { FlatList } from 'react-native';

export function ProductFeed({ products }) {
  return (
    <FlatList
      data={products}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <ProductCard product={item} />}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
    />
  );
}
// Po: FlashList v2
import { FlashList } from '@shopify/flash-list';

export function ProductFeed({ products }) {
  return (
    <FlashList
      data={products}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <ProductCard product={item} />}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
    />
  );
}

Pre heterogénne zoznamy (rôzne typy položiek) pridajte getItemType. Toto je jediná vec, ktorú FlatList nemá a ktorá výrazne pomôže s recykláciou:

<FlashList
  data={feed}
  keyExtractor={(item) => item.id}
  getItemType={(item) => {
    // Vráti reťazec, ktorý identifikuje typ položky.
    // FlashList recykluje len v rámci rovnakého typu.
    return item.kind; // 'ad' | 'product' | 'banner'
  }}
  renderItem={({ item }) => {
    if (item.kind === 'ad') return <AdCard item={item} />;
    if (item.kind === 'banner') return <Banner item={item} />;
    return <ProductCard item={item} />;
  }}
/>

Kľúčové props pre optimalizáciu výkonu

FlashList v2 odviedol veľký kus optimalizácie za vás, ale niekoľko props-ov má stále veľký dopad. Toto sú tie, ktoré v praxi konfigurujem ako prvé.

drawDistance

Hovorí FlashListu, koľko pixelov pred a za viewport-om má pre-render-ovať. Predvolená hodnota je 250 px. Pre obrazovky s ťažkými obrázkami zvyknem zvýšiť na 500 až 800, čo redukuje blank frames pri rýchlom flingu. Pre jednoduché text-only zoznamy môžete znížiť na 100, čo ušetrí RAM.

maintainVisibleContentPosition

Veľmi užitočný pri chat-och a infinite scroll-och, kde nové položky pribúdajú na vrchu. Predtým bol potrebný hack cez onContentSizeChange; FlashList v2 ho má ako prvotriedny prop.

<FlashList
  data={messages}
  renderItem={renderMessage}
  inverted
  maintainVisibleContentPosition={{
    autoscrollToTopThreshold: 10,
    startRenderingFromBottom: true,
  }}
/>

onLoad

Callback, ktorý firne, keď je prvá várka položiek vyrenderovaná. Toto je správny moment na skrytie skeleton screen-u. Nepoužívajte useEffect nad data.length, lebo vás predbehne (a áno, tento footgun som si v jednom projekte odskákal).

contentContainerStyle paddingBottom

Klasický footgun: ak používate tab bar alebo floating button, dajte contentContainerStyle={{ paddingBottom: 100 }}, nie style. Posledné položky inak vždy zostanú schované pod overlay-om.

Funguje FlashList s Novou architektúrou?

FlashList v2 funguje výhradne s Novou architektúrou. Nie je to opcia, je to požiadavka. Knižnica predpokladá, že Shadow Tree je dostupný synchrónne a že môže volať priamo do C++ layout primitív. Na Starej architektúre (Paper) by to znamenalo bridge cez async messages, čo by zničilo celú perf výhru.

Ak ešte máte projekt na Paper-i, máte dve cesty. Prvá je zostať na FlashList v1, ktorý je naďalej udržiavaný (security fixes), ale nedostáva nové features. Druhá je migrácia na New Architecture, čo je v 2026 už pomerne bezbolestné. Pre väčšinu projektov stačí zapnúť newArchEnabled: true v app.json a otestovať. Detailný postup som popísal v sprievodcovi Expo SDK 55 a Nová architektúra.

Treba si dať pozor na natívne komponenty tretích strán, ktoré ešte nemajú Fabric/TurboModule binding. Typicky niektoré staré video playery alebo SDK-čka pre platobné brány. Pred migráciou si urobte audit cez npx react-native config a skontrolujte stĺpec „interop layer".

Masonry layout a horizontálne zoznamy

Jeden z najčastejších dôvodov, prečo som v projektoch siahal po FlashList aj keď FlatList by stačil, je Pinterest-style masonry layout. V FlatList si museli ľudia pomáhať react-native-masonry-list, ktorý nebol udržiavaný od 2023. FlashList v2 má masonry natívne cez masonry prop.

<FlashList
  data={photos}
  numColumns={2}
  masonry
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => (
    <Image
      source={{ uri: item.url }}
      style={{ aspectRatio: item.aspectRatio, width: '100%' }}
    />
  )}
/>

Horizontálne zoznamy fungujú cez prop horizontal presne ako pri FlatList. Pre carousely odporúčam ešte snapToInterval alebo kombináciu s Reanimated useSharedValue a useAnimatedScrollHandler pre custom snap logic.

FlashList vs LegendList v roku 2026

LegendList od tímu Legend State je v 2026 najreálnejší konkurent. Má agresívnejšie pre-renderovanie a v synthetic benchmark-och niekedy poráža FlashList o 5 až 10 % FPS. Reálne ho ale zatiaľ neodporúčam pre produkčné nasadenie z dvoch dôvodov.

Prvý je ekosystém. FlashList používa Shopify, Discord, Bloomberg, Mercari, takže máme tisíce hodín produkčných dát a veľmi dobrý track record bug fixov. LegendList má v čase písania zhruba 6 mesiacov v produkcii a stále vidíme edge cases s maintainVisibleContentPosition.

Druhý je API. LegendList vyžaduje, aby data prešli cez ich vlastný observable systém, čo je v poriadku, ak používate Legend State ako state manager. Ak používate Zustand, Jotai alebo TanStack Query (čo popisujem v článku Správa stavu v React Native 2026), pridávate ďalšiu vrstvu len kvôli zoznamu.

Moje odporúčanie pre rok 2026: FlashList v2 ako default. LegendList sledujte, dajte mu rok produkčnej zrelosti a potom prehodnoťte. Podobne to vidím aj pri voľbe testovacieho nástroja, čo rozoberám v článku Maestro vs Detox v 2026: ekosystém a stabilita zvyčajne porazia syntetické benchmarky.

Časté chyby a ako sa im vyhnúť

Tieto chyby vidím v code reviews najčastejšie a stojí za to im venovať minútu.

Inline funkcie v renderItem

Ak renderItem definujete inline (čo je default v React Native dokumentácii), pri každom rendri rodičovskej komponenty vznikne nová funkcia. FlashList nedokáže optimálne recyklovať, lebo si myslí, že sa zmenil typ položky. Riešenie: definujte renderItem ako useCallback alebo, ešte lepšie, ako samostatnú komponentu mimo parent-a.

Chýbajúci getItemType pri heterogénnych dátach

Ak miešate reklamy, bannery a produkty v jednom feed-e a nemáte getItemType, FlashList sa pokúsi recyklovať banner ako reklamu. Výsledkom je flickering a niekedy aj crash, ak typy majú rôzne native views. Vždy definujte typ. (Túto chybu som naposledy lovil pri shipovaní v3 nášho retail feed-u a stála ma celý piatkový večer.)

Pevné výšky cez style namiesto wrapper-u

FlashList meria položky cez ich root view. Ak má položka onLayout handler, ktorý mení svoju výšku po mount-e, knižnica musí preverenie spraviť dvakrát. Snažte sa, aby každá položka mala stabilnú výšku už pri prvom renderingu, použite aspectRatio pre obrázky a placeholders pre lazy data.

Nesprávne použitie keyExtractor

Index ako kľúč ((_, i) => i.toString()) láme recykláciu pri pridávaní/odoberaní položiek. Vždy použite stabilný ID. Ak ho dáta nemajú, vygenerujte ho cez UUID pri fetch-i a držte v cache.

Pre hlbší ponor do zoznamov a navigácie odporúčam aj môj sprievodca Expo Router v6, kde rozoberám, ako kombinovať FlashList s tab navigáciou bez stratených scroll pozícií. Pre ďalšie detaily o samotnej knižnici sa pozrite na oficiálnu dokumentáciu FlashList, GitHub release notes a porovnanie s pôvodným návodom na optimalizáciu FlatList z React Native dokumentácie.

Často kladené otázky

Potrebujem stále nastavovať estimatedItemSize vo FlashList v2?

Nie. Prop estimatedItemSize bol vo verzii 2.0 odstránený. FlashList teraz meria položky synchrónne počas mount-u priamo cez Yoga layout engine vo Fabric-u, takže nepotrebuje odhad od vývojára. Ak ho v kóde máte z v1, jednoducho ho zmažte, TypeScript vám ho aj tak nahlási ako neznámy prop.

Funguje FlashList v2 v Expo Go?

Nie. FlashList v2 obsahuje natívny kód, ktorý Expo Go nemá prebuildovaný. Musíte si vytvoriť custom development client cez npx expo run:ios alebo cez EAS Build. Pre rýchle testovanie môžete použiť Expo Dev Client s pridaným FlashList plugin-om.

Môžem používať FlashList v1 a v2 v rovnakom projekte?

Technicky áno cez aliasing v package.json, ale neodporúčam to. Verzie majú odlišné peer dependencies a v ladení vznikajú nečakané edge cases. Lepšie je vybrať si jednu verziu na celý projekt a migrovať atomicky.

Ako otestujem FlashList v Jest testoch?

Použite @testing-library/react-native verziu 12.5+ s mockom jest.mock('@shopify/flash-list', () => require('@shopify/flash-list/jestSetup')). Knižnica poskytuje oficiálny test setup, ktorý nahradí natívne komponenty React Native ScrollView wrapper-om, takže renderItem sa volá synchrónne počas testu.

Aký je rozdiel medzi getItemType a getItemLayout?

getItemType hovorí FlashListu, aký typ view má vytvoriť, knižnica potom recykluje len medzi položkami rovnakého typu. getItemLayout z FlatList API neexistuje v FlashList v2, pretože všetky merania prebiehajú automaticky. Pre miešané feed-y používajte getItemType; pre rovnaké položky netreba nič.

Jake Morrison
O Autorovi Jake Morrison

React Native lead engineer who's shipped six apps and learned six different lessons. Bullish on the New Architecture.