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

FlatList vs FlashList: Cum am salvat FPS-ul pe Android entry-level

De Alin Pătrașcu, 11 iun. 2026 · 15 vizualizări · 3 like-uri

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

interface Product {
  id: string;
  title: string;
  price: string;
}

export const ProductList = ({ products }: { products: Product[] }) => {
  return (
    <FlashList
      data={products}
      renderItem={({ item }) => (
        <View style={{ height: 100, padding: 10 }}>
          <Text>{item.title}</Text>
          <Text>{item.price}</Text>
        </View>
      )}
      // Valoare critică! Trebuie să fie media înălțimii randate a unui item
      estimatedItemSize={100}
      keyExtractor={(item) => item.id}
    />
  );
};

Am testat FlashList de la Shopify pe un Samsung A12 obosit, genul de telefon pe care îl primești cadou la un abonament de zece euro. Am vrut să văd dacă hype-ul din comunitate este real sau e doar marketing de la băieții din e-commerce. Rezultatele pe Android entry-level sunt noaptea și ziua dacă ai liste lungi. Dacă vrei ca aplicația ta să nu mai agațe la scroll rapid, hai să îți zic ce am măsurat și unde se împute treaba.

Testul din viața reală: 2.500 de produse cu imagini

Am avut de implementat un feed de produse pentru un magazin local. Nimic SF: o imagine, un titlu, un preț și un buton de adaugă în coș. Pe un iPhone recent sau pe un emulator de Mac totul zbura la 60 FPS, evident.

Problema a apărut când am rulat release-ul pe Samsung-ul ăla ieftin. Folosind clasicul FlatList din React Native, FPS-ul pe JS thread scădea dramatic la 12-15 FPS în timpul unui scroll mai agresiv. Utilizatorul vedea ecrane albe fiindcă thread-ul de JS nu apuca să randeze destul de repede componentele din listă. Practic, experiența era inutilizabilă.

De ce moare FlatList și cum ajută FlashList

Problema de bază la FlatList este că el creează și distruge componente React pe măsură ce utilizatorul scrollează. Când un element iese din ecran, este distrus. Când intră altul, este instanțiat. Chestia asta pune o presiune imensă pe Garbage Collector-ul din motorul JS (Hermes, în cazul nostru).

FlashList funcționează complet diferit. Folosește conceptul de "cell recycling" împrumutat din dezvoltarea nativă (RecyclerView pe Android și UICollectionView pe iOS). În loc să distrugă componentele vechi, le păstrează în memorie și doar le injectează datele noi.

După ce am înlocuit FlatList cu FlashList, cifrele din Perf Monitor s-au schimbat radical pe același dispozitiv entry-level:

  • JS FPS: A urcat de la ~15 la un stabil 55-58 FPS.
  • UI FPS: A rămas constant la 60 FPS.
  • Timpul de randare inițial: A scăzut cu aproape 30%.
  • Zone albe (blank areas): Au dispărut aproape complet în timpul scroll-ului normal.

Trade-off-ul sincer: Nu e totul lapte și miere

Deși sună ca soluția magică, reciclarea asta vine cu niște costuri de dezvoltare de care trebuie să fii conștient.

În primul rând, dacă ai stare internă în elementele din listă (de exemplu, un checkbox local de isExpanded), starea aia va rămâne pe componenta reciclată. Când scrollezi, te vei trezi că alte produse din listă apar bifate aiurea. Toată starea trebuie mutată în parent sau într-un store global.

În al doilea rând, proprietatea estimatedItemSize este critică. Dacă pui o valoare complet greșită (de exemplu pui 50 de pixeli, dar elementul tău are în realitate 250), FlashList va recalcula layout-ul din mers și vei avea niște sărituri (layout jumps) extrem de deranjante vizual.

FlashList merită cu vârf și îndesat dacă ai liste complexe sau infinite pe Android low-end. Dacă ai doar liste scurte de 20-30 de elemente simple, rămâi pe FlatList și scutește-te de bug-uri legate de reciclare.

Voi ce folosiți pentru listele grele din producție?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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