eduardweb.
React Native & ExpoIntermediar#performance#react-native#android#flashlist

FlatList vs FlashList pe Android ieftin: Cum am trecut de la 12 la 58 FPS

De Ioana Marinescu, 20 iun. 2026 · 15 vizualizări · 2 like-uri

Postat 20 iun. 2026
typescript
import React from 'react';
import { Text, View } from 'react-native';
import { FlashList } from '@shopify/flash-list';

interface ListItem {
  id: string;
  type: 'product' | 'banner';
  title: string;
}

const ProductList = ({ data }: { data: ListItem[] }) => {
  return (
    <FlashList
      data={data}
      renderItem={({ item }) => (
        <View style={{ height: item.type === 'banner' ? 200 : 100 }}>
          <Text>{item.title}</Text>
        </View>
      )}
      estimatedItemSize={120}
      getItemType={(item) => item.type}
      keyExtractor={(item) => item.id}
    />
  );
};

Am avut recent de optimizat un feed infinit pentru o aplicație de e-commerce cu vreo 12.000 de produse active. Pe iPhone 13 Pro totul mergea impecabil, dar când am testat pe un Samsung A12 (un entry-level clasic pe care îl ținem în birou pentru teste de stres), realitatea ne-a dat o palmă: FPS-ul pe JS thread scădea la 8-10 în timpul scroll-ului rapid.

Soluția clasică cu FlatList pur și simplu nu mai făcea față, indiferent de câte optimizări făceam cu windowSize, maxToRenderPerBatch sau initialNumToRender. Am decis să migrăm pe @shopify/flash-list și am măsurat diferențele direct cu Perf Monitor-ul din meniul de developer.

De ce moare FlatList pe telefoane slabe

Problema cu FlatList e legată de cum gestionează memoria. Când dai scroll, el creează componente noi de React și le distruge pe cele care ies din ecran. Pe un procesor MediaTek ieftin, procesul ăsta de mount/unmount generează un garbage collection agresiv.

Practic, JS thread-ul rămâne blocat încercând să calculeze layout-ul noilor elemente, iar utilizatorul vede acele zone albe (blank spaces) secunde bune până când se randează conținutul.

Cum ne-a salvat FlashList (și cifrele reale)

Spre deosebire de FlatList, FlashList folosește conceptul de reciclare a celulelor (similar cu RecyclerView din Android nativ). În loc să distrugă componentele care ies din vizor, el le păstrează în memorie și le reutilizează structura, schimbând doar datele din props.

Am pornit Perf Monitor pe Samsung A12 și am făcut un test de scroll continuu timp de 30 de secunde:

  • FlatList: UI FPS a oscilat între 25 și 35. JS FPS a scăzut dramatic, atingând minime de 6 FPS. Zonele albe apăreau la fiecare 2-3 secunde.
  • FlashList: UI FPS s-a menținut stabil la 55-58 FPS. JS FPS nu a scăzut sub 42 FPS. Zero ecrane albe, scroll-ul s-a simțit fluid, aproape ca într-o aplicație nativă.

Am economisit cam 40% din timpul de procesare pe JS thread doar din această schimbare.

Trade-off-ul de care nu vorbește nimeni

Deși FlashList pare un glonț de argint, am dat de câteva bube la implementare. Cel mai mare chin a fost cu estimatedItemSize. Dacă pui o valoare greșită, lista va avea salturi vizuale urâte (layout jumps) când utilizatorul dă scroll înapoi. Trebuie să calculezi o medie cât mai exactă a înălțimii unui rând.

De asemenea, dacă ai liste cu tipuri de elemente complet diferite (de exemplu, un rând cu produs, urmat de un banner publicitar mare), trebuie neapărat să folosești prop-ul getItemType. Altfel, FlashList va încerca să recicleze layout-ul produsului pentru banner și aplicația va afișa elemente complet deformate.

La final, pentru noi migrarea a fost un no-brainer. Am obținut o fluiditate pe care nu credeam că o putem scoate dintr-un React Native rulat pe un hardware de 150 de euro. Voi ați trecut complet pe FlashList în producție sau încă preferați să stoarceți ultimele resurse din FlatList-ul nativ?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.