import React from 'react';
import { Text, View } from 'react-native';
import { FlashList } from '@shopify/flash-list';
interface Product {
id: number;
title: string;
}
export const MyCatalog = ({ products }: { products: Product[] }) => {
return (
<FlashList
data={products}
renderItem={({ item }) => (
<View style={{ height: 80, padding: 10 }}>
<Text>{item.title}</Text>
</View>
)}
estimatedItemSize={80} // Extrem de important pentru a evita stutter-ul pe Android!
keyExtractor={(item) => item.id.toString()}
/>
);
};Am testat FlashList de la Shopify pe o rablă de telefon de acum 4 ani ca să văd dacă chiar merită efortul de migrare de la clasicul FlatList. Dacă ai probleme cu drop-uri de cadre pe Android-urile ieftine când userul dă scroll rapid, cifrele de mai jos o să-ți arate exact la ce să te aștepți. Spoiler: diferența pe Perf Monitor e de la cer la pământ.
Contextul: Un Samsung A12 și 12.000 de produse
La un proiect recent, am avut de randat un catalog de produse destul de stufos, cam 12.000 de iteme cu imagini luate din API și ceva text. Pe iPhone 13 sau pe simulatoarele de pe Mac totul mergea brici cu FlatList la 60 FPS. Însă când am pus build-ul pe un Samsung A12 (un entry-level clasic pe care îl țin special pentru teste de performanță), frame rate-ul pe JS thread a picat instant la 15-18 FPS la un scroll mai agresiv.
Userul vedea ecrane albe (acele blank spaces enervante) pentru că JS thread-ul pur și simplu nu ținea pasul cu randarea elementelor din listă. FlatList continuă să monteze și să demonteze noduri în React, punând o presiune imensă pe garbage collector-ul de JavaScript.
Cifrele din Perf Monitor: FlatList vs FlashList
Am decis să fac trecerea la FlashList și să măsor diferența folosind Perf Monitor-ul nativ din Developer Menu. Rezultatele m-au făcut să nu mă mai întorc niciodată la FlatList pentru liste mari.
- FlatList: UI Thread: ~42 FPS | JS Thread: 12-18 FPS (scroll rapid). Zone albe masive pe ecran.
- FlashList: UI Thread: 58-60 FPS | JS Thread: 52-55 FPS (scroll rapid). Randare aproape instantanee.
Am economisit cam 30% din timpul de CPU pe JS thread doar prin această schimbare. Secretul celor de la Shopify este reciclarea views-urilor. În loc să distrugă componentele care ies din ecran și să creeze altele noi (cum face FlatList), FlashList păstrează structura nativă de view și doar schimbă datele din ea (re-bind). Este exact ce fac iOS (UICollectionView) și Android (RecyclerView) nativ de peste un deceniu.
Trade-off-ul sincer: Nu e totul doar lapte și miere
Deși sună ca o soluție magică, FlashList vine cu un compromis destul de enervant. Trebuie să-i pasezi proprietatea estimatedItemSize.
Dacă ai o listă unde înălțimea elementelor variază masiv (de exemplu, un element are 100px, altul are 400px pentru că are imagine mare, iar altul are doar un rând de text), FlashList o să aibă momente de „stutter” (agățat) vizibil pe Android în timp ce recalculează dimensiunile din mers.
Dacă valoarea din estimatedItemSize este departe de media reală a înălțimii elementelor tale, performanța scade drastic și riști să ai elemente care se suprapun vizual pentru o fracțiune de secundă.
Concluzia mea
FlashList câștigă detașat când ai liste lungi cu elemente relativ uniforme ca dimensiune. Pentru feed-uri complexe cu 10 tipuri de layout-uri diferite și înălțimi complet dinamice, s-ar putea să te chinui mult cu debugging-ul vizual și cu proprietatea getItemType ca să eviți glitch-urile.
Voi ce folosiți în producție pentru listele mari? Ați rămas pe FlatList cu parametrii de windowSize și maxToRenderPerBatch optimizați la sânge sau ați făcut deja trecerea?