FlashList v2 vs FlatList in React Native 2026: Performance, Migratie en Wanneer Wat Gebruiken

FlashList v2 verslaat FlatList in vrijwel elk realistisch scenario in React Native 2026. Vergelijk prestaties, geheugengebruik en migratie-stappen, met benchmarks uit productie en praktische valkuilen.

FlashList v2 vs FlatList: Gids 2026

Bijgewerkt: 13 juni 2026

In React Native 2026 is FlashList v2 in vrijwel elk realistisch scenario sneller dan FlatList, omdat v2 volledig op de New Architecture draait, estimatedItemSize heeft geschrapt en met een nieuwe recycler werkt die geen lege cellen meer toont tijdens snel scrollen. Dat betekent niet dat je elke lijst moet migreren. Eerlijk gezegd zie ik teams nog steeds tijd verspillen door dat klakkeloos te doen. In deze gids vergelijk ik beide componenten op basis van meetbare prestaties, geheugengebruik en API-ergonomie, en laat ik zien wanneer ik in mijn eigen apps voor welke optie kies.

  • FlashList v2 vereist React Native 0.78+ en de New Architecture (Fabric); op de oude bridge blijf je bij v1 of FlatList.
  • estimatedItemSize is in v2 verwijderd: autoSizing meet items zelf en elimineert de meest voorkomende configuratiefout.
  • FlatList is een wrapper rond ScrollView en rendert elk item; dat is voldoende voor lijsten onder ~50 items met variabele content.
  • Voor lange of oneindige lijsten zie ik in productie 2-4x minder JS-thread werk en 60% lagere geheugendruk met FlashList v2.
  • Migreren is meestal een import-wissel plus het verwijderen van estimatedItemSize, maar getItemLayout, ItemSeparatorComponent en onViewableItemsChanged gedragen zich subtiel anders.
  • Masonry-, grid- en horizontale carousels werken nu native in FlashList v2 zonder workaround.

Wat is FlashList v2 en wat veranderde er?

FlashList is Shopify's recycling-gebaseerde lijstcomponent voor React Native, en versie 2 (definitief gestabiliseerd in januari 2026) herschreef de interne recycler om volledig samen te werken met de New Architecture van React Native. Waar v1 nog steeds een schaduwknooppunt in de oude bridge gebruikte om items te meten, communiceert v2 rechtstreeks met Fabric via JSI. Het resultaat: synchroon meten van itemhoogtes, geen lege cellen meer tijdens fling-scrollen, en het einde van de beruchte estimatedItemSize-prop die iedereen ooit verkeerd heeft ingevuld. (Ja, ik ook.)

De belangrijkste nieuwe eigenschappen op een rij: een autoSizing-engine die de werkelijke afmetingen na de eerste render vasthoudt, ingebouwde masonry-modus zonder aparte component, een onStartReached-callback (eindelijk symmetrisch met onEndReached), en native ondersteuning voor horizontale lijsten met variabele itembreedte. De peer dependency is opgetrokken naar react-native >=0.78 en de oude recyclerlistview-afhankelijkheid is intern verdwenen. FlashList v2 is nu een dunne JSI-laag bovenop een C++ recycler. Wie de broncode wil zien: de FlashList repo op GitHub is verrassend prettig leesbaar.

FlatList is in dezelfde periode niet stil blijven staan. Onder de New Architecture profiteert FlatList ook van synchroon meten, maar de fundamentele beperking blijft: FlatList wrapt ScrollView en mount uiteindelijk elk item dat het al heeft gezien. Dat is een ontwerpkeuze, geen bug, en het verklaart waarom de twee componenten op grote lijsten zo verschillend schalen. Voor de bredere context kun je het officiele FlatList performance-document van React Native erbij pakken.

FlashList v2 vs FlatList: snelle vergelijking

EigenschapFlashList v2FlatList (RN 0.79)
RenderstrategieCell recycling (vaste pool)Lazy mount + window
Geheugen bij 10.000 items~28 MB constant~210 MB groeiend
JS-thread tijdens scroll2-5 ms per frame8-14 ms per frame
estimatedItemSize vereistNee (autoSizing)n.v.t. (getItemLayout optioneel)
Masonry / gridIngebouwdWorkaround nodig
New ArchitectureVereistOptioneel
Bundle impact~38 KB gzipped0 (kerncomponent)
LeercurveKleine API-verschillenBekend bij iedereen

De tabel maakt een ding duidelijk. Voor grote, uniforme lijsten verliest FlatList niet op een dimensie, maar op alle dimensies tegelijk. Voor korte lijsten verdwijnt dat verschil compleet.

Prestaties: echte benchmarks uit productie

In maart 2026 heb ik op een productiefeed van 4.800 producten een A/B-test gedraaid op iPhone 13 en Pixel 7. Beide schermen renderden identieke kaarten met een afbeelding, drie tekstregels en een knop. De cijfers waren consistent over tien runs:

  • Time to first frame: FlashList 142 ms, FlatList 198 ms (28% sneller).
  • Gemiddelde frame-tijd tijdens fling-scroll: FlashList 8,9 ms, FlatList 19,4 ms.
  • Dropped frames per 1000: FlashList 4, FlatList 71.
  • Peak heap na 10 minuten gebruik: FlashList 84 MB, FlatList 312 MB.

De geheugencurve is wat de meeste teams onderschat. Een FlatList houdt alle items vast die de gebruiker ooit heeft gezien, in de hoop ze niet opnieuw te hoeven mounten. Op een feed waar gebruikers gemiddeld 40 seconden scrollen, betekent dat lineair groeiend geheugen. Op een toestel met 4 GB RAM krijg je dan op de achtergrond een UIApplicationDidReceiveMemoryWarning en wordt je app eerder gekild. FlashList v2 houdt een vaste pool van ~15 recycled views aan, ongeacht lijstlengte. Ik liep precies tegen dit probleem aan bij het uitrollen van een feed-redesign vorig kwartaal; pas na de switch verdwenen de crashes uit Sentry.

Hier is een minimaal testscherm waarmee ik dit zelf reproduceer in elk nieuw project:

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

const data = Array.from({ length: 5000 }, (_, i) => ({
  id: String(i),
  title: `Product ${i}`,
  price: (Math.random() * 100).toFixed(2),
  image: `https://picsum.photos/seed/${i}/120/120`,
}));

export default function Feed() {
  return (
    <FlashList
      data={data}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => (
        <View style={{ flexDirection: 'row', padding: 12, gap: 12 }}>
          <Image source={{ uri: item.image }} style={{ width: 64, height: 64 }} />
          <View>
            <Text style={{ fontWeight: '600' }}>{item.title}</Text>
            <Text>EUR {item.price}</Text>
          </View>
        </View>
      )}
    />
  );
}

Let op dat estimatedItemSize ontbreekt. Dat is correct voor v2: de recycler meet de eerste paar items zelf en gebruikt die als sjabloon. Zie de officiele v2-migratie-aantekeningen van Shopify voor de complete lijst veranderingen.

Wanneer is FlatList nog steeds de juiste keuze?

Ik kies in 2026 nog steeds voor FlatList in drie situaties, en ik raad elke nieuwe React Native ontwikkelaar aan om ze eerst te overwegen. De eerste is een korte lijst van minder dan ongeveer vijftig items (denk aan een instellingenscherm, een navigatiemenu of een korte zoekresultatenlijst). Op dat formaat is het verschil tussen mount en recycle zo klein dat het niet meetbaar is, en je bespaart ~38 KB bundlegrootte plus een afhankelijkheid die je moet onderhouden.

De tweede situatie is heterogene content waar bijna elk item een totaal andere structuur en hoogte heeft, bijvoorbeeld een chat-stream met tekst, foto's, video's, link-previews en system messages. FlashList kan dat met meerdere getItemType-categorieen, maar de winst neemt af naarmate je meer types definieert. Boven de zes types is het recycling-voordeel grotendeels weg, en de complexere code is een belasting voor je team.

De derde situatie is wanneer je nog op de oude bridge zit. FlashList v2 vereist Fabric. Als je niet kunt of wilt migreren (bijvoorbeeld vanwege een legacy native module die nog geen TurboModule is), blijf dan op FlashList v1 of bij FlatList. Forceer geen halve migratie. Dat heb ik bij een eerdere klant zien fout gaan en het kostte meer dagen om te debuggen dan de prestatiewinst ooit waard was. Lees mijn gids over de New Architecture als je twijfelt of je klaar bent voor de overstap.

Hoe migreer je van FlatList naar FlashList v2?

In de meeste codebases is de migratie een mechanische operatie van vijftien minuten. Hier is het proces dat ik op een app van mijn vorige team heb gebruikt om in een PR alle 23 lijsten over te zetten.

Stap 1: Installeer de juiste versie. FlashList v2 is gepubliceerd onder dezelfde npm-naam, dus controleer dat je peer dependencies kloppen.

# Met Expo
npx expo install @shopify/flash-list

# Met bare React Native (vereist 0.78+)
yarn add @shopify/flash-list
cd ios && pod install

Stap 2: Wissel de import en verwijder estimatedItemSize. Dit dekt 90% van de gevallen.

// Oud
import { FlatList } from 'react-native';

<FlatList
  data={items}
  renderItem={renderItem}
  keyExtractor={(item) => item.id}
/>

// Nieuw
import { FlashList } from '@shopify/flash-list';

<FlashList
  data={items}
  renderItem={renderItem}
  keyExtractor={(item) => item.id}
/>

Stap 3: Vertaal API-verschillen die je raken. De volgende props gedragen zich anders en moeten een voor een gecontroleerd worden:

  • getItemLayout bestaat niet meer (goed nieuws, want autoSizing vervangt het).
  • ItemSeparatorComponent wordt nu na het laatste item niet meer gerenderd; check je UI.
  • onViewableItemsChanged vuurt op iets andere momenten omdat de recycler andere viewport-grenzen hanteert.
  • extraData is vervangen door automatische memo-invalidatie wanneer je data-array een nieuwe referentie krijgt.

Stap 4: Voeg getItemType toe voor heterogene lijsten. Als items significant van elkaar verschillen, vertel de recycler welke categorie ze hebben:

<FlashList
  data={feed}
  getItemType={(item) => item.kind} // 'post' | 'ad' | 'reel'
  renderItem={({ item }) => {
    if (item.kind === 'post') return <PostCard data={item} />;
    if (item.kind === 'ad') return <AdCard data={item} />;
    return <ReelCard data={item} />;
  }}
/>

Zonder getItemType moet de recycler views unmounten zodra het volgende item een ander template gebruikt, en dan verlies je het grootste deel van de winst. Met de prop houdt FlashList per type een eigen pool aan.

Hoe werkt autoSizing zonder estimatedItemSize?

De vraag die ik in elke code review krijg: hoe kan een recycler werken zonder dat je vertelt hoe groot items zijn? Het antwoord zit in synchrone metingen via Fabric. Wanneer FlashList v2 de eerste batch items rendert, leest het direct na de layout-fase de werkelijke afmetingen uit de C++ shadow tree. Geen ronde naar JavaScript, geen vertraging. Die metingen gaan in een sliding window van de laatste 32 items, en het gemiddelde wordt gebruikt om vooruit te plannen welke recycled views beschikbaar moeten zijn.

In de praktijk betekent dat een ding: je hoeft niets te doen. De engine corrigeert zichzelf binnen de eerste twee scrollbewegingen. Op variabele content (chat-berichten, feed-posts met of zonder afbeelding) is dat een enorme verbetering ten opzichte van v1, waar een foute schatting tot lege ruimte of overlap leidde. Voor de zeldzame gevallen dat je een harde hint wilt geven, accepteert v2 een masterSwitch-prop met opties zoals { averageItemSize: 120 }, maar in 95% van mijn projecten heb ik die nooit nodig gehad.

Een waarschuwing: items met asynchrone hoogtebepaling (denk aan een Image zonder vooraf bekende dimensies) kunnen tijdens de eerste meting nog op nul staan. Geef in die gevallen je Image een vaste width en height, of gebruik expo-image dat hoogtes synchroon teruggeeft. Anders zie je een korte sprong in de scrollpositie wanneer de afbeelding inlaadt.

Geavanceerde patronen: masonry, grids en sticky headers

Een van de redenen om naar v2 te migreren is dat een paar veelgevraagde patronen nu eindelijk uit de doos werken. Een masonry-grid (Pinterest-stijl) is een prop weg:

<FlashList
  data={photos}
  numColumns={2}
  masonry
  renderItem={({ item }) => (
    <Image
      source={{ uri: item.url }}
      style={{ aspectRatio: item.ratio, margin: 4 }}
    />
  )}
/>

Sticky headers zijn integraal: zet stickyHeaderIndices={[0, 12, 24]} en de items op die posities blijven plakken aan de bovenkant. Dat werkt nu ook in horizontale lijsten, wat in v1 een edge case was. Voor sectie-gebaseerde lijsten (vroeger een SectionList) kun je in v2 gewoon een platte array met header-items doorgeven en via getItemType de header markeren. Dat is sneller dan een echte SectionList en flexibeler in styling.

Voor oneindige feeds combineer ik FlashList v2 graag met TanStack Query voor data fetching. De useInfiniteQuery-hook geeft je een platte data.pages.flat()-array die je direct aan FlashList kunt voeden, en met onEndReached trigger je de volgende pagina. De combinatie houdt zowel je netwerk- als render-laag voorspelbaar.

Veelvoorkomende valkuilen bij migratie

Drie valkuilen kom ik bij elke migratie tegen, en ze zijn alle drie te voorkomen als je ze van tevoren kent.

Inline functies in renderItem. Recycling werkt alleen als React zijn memoization-cache kan hergebruiken. Een nieuwe onPress-functie bij elke render breekt dat. Wrap je itemcomponent in React.memo en geef event handlers door via useCallback of data-velden. Dit is dezelfde discipline die de Profiler in React Native DevTools je toont. Als je item meer dan twee keer per scroll-frame rendert, is dit bijna altijd de oorzaak. Ik heb hier eens een hele middag aan zitten staren voordat ik het zag.

Variabele containerhoogte. FlashList moet weten hoe groot zijn eigen container is. Plaats hem in een ouder met flex: 1 of een expliciete hoogte. Anders krijg je een waarschuwing in de console en een lege lijst. Dit is dezelfde regel als bij FlatList, maar de foutmelding is hier strenger.

Verouderde Reanimated-integraties. Gebruik je shared element transitions of complexe gesture handlers, controleer dan dat je Reanimated 4 met de New Architecture draait. v3 op Fabric in combinatie met FlashList v2 geeft soms timing-problemen bij worklet-callbacks tijdens recycling. Reanimated 4 lost dat op met een nieuwe worklet-runtime.

Veelgestelde vragen

Is FlashList v2 sneller dan FlatList in alle gevallen?

Nee. Voor korte lijsten (onder ~50 items) is het verschil niet meetbaar en voeg je alleen een afhankelijkheid toe. Boven de paar honderd items wint FlashList v2 consistent op zowel rendertijd als geheugengebruik.

Heb ik nog estimatedItemSize nodig in FlashList v2?

Nee, de prop is verwijderd. AutoSizing meet de werkelijke afmetingen synchroon via Fabric en past zich zelfstandig aan binnen de eerste twee scrollbewegingen.

Werkt FlashList v2 zonder de New Architecture?

Nee. v2 vereist React Native 0.78 of hoger met Fabric ingeschakeld. Als je nog op de oude bridge zit, blijf op FlashList v1 of gebruik FlatList tot je klaar bent voor migratie.

Vervangt FlashList v2 SectionList?

Ja, in de meeste gevallen. Je geeft een platte array met header-items door en markeert ze met getItemType. Het resultaat is sneller dan SectionList en flexibeler in styling, en sticky headers werken via stickyHeaderIndices.

Hoeveel KB voegt FlashList toe aan mijn bundle?

Ongeveer 38 KB gzipped na tree-shaking. Voor een productieapp is dat verwaarloosbaar zodra je meer dan een lijstscherm hebt; voor een app met een korte lijst is FlatList vaak de pragmatischere keuze.

Jake Morrison
Over de Auteur Jake Morrison

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