import React, { memo, useCallback } from 'react';
import { Text, TouchableOpacity } from 'react-native';
import { FlashList } from '@shopify/flash-list';
interface ItemProps {
id: string;
title: string;
onPress: (id: string) => void;
}
// Memorizăm doar elementele complexe din listă
const TransactionRow = memo(({ id, title, onPress }: ItemProps) => {
return (
<TouchableOpacity onPress={() => onPress(id)} style={{ height: 60, padding: 10 }}>
<Text>{title}</Text>
</TouchableOpacity>
);
}, (prevProps, nextProps) => prevProps.id === nextProps.id); // Custom comparison opțional
export function MyList({ data }: { data: { id: string; title: string }[] }) {
// useCallback își are rostul acum pentru că TransactionRow e memoizat
const handlePress = useCallback((id: string) => {
console.log('Item selected:', id);
}, []);
return (
<FlashList
data={data}
renderItem={({ item }) => (
<TransactionRow id={item.id} title={item.title} onPress={handlePress} />
)}
estimatedItemSize={60} // Parametru critic pentru FlashList
keyExtractor={(item) => item.id}
/>
);
}Am văzut prea multe codebase-uri de React Native în care problemele de performanță sunt tratate cu un fel de magie voodoo: „pune și tu useMemo și useCallback peste tot și vedem după”. Adevărul e că optimizarea asta făcută după ureche adaugă overhead de memorie și adesea face mai mult rău decât bine. JS thread-ul ajunge să compare dependințe la fiecare randare pentru niște funcții banale care oricum se recreau instat.
Hai să demitizăm puțin zona asta. Am trecut prin destule ecrane care mergeau în 15 FPS pe telefoane de buget și m-am lovit direct de limitele vechiului FlatList.
Obsesia cu useCallback și useMemo
Mulți juniori cred că dacă pasează o funcție inline ca prop, gata, crapă aplicația. Nu e așa. Crearea unei funcții în JS este incredibil de ieftină. Problema apare doar dacă acel prop forțează un sub-arbore masiv de componente să se randeze inutil.
Am avut cazul unui ecran de tip dashboard la un proiect cu peste 8.000 de utilizatori activi zilnic. Aveam o listă de tranzacții. Foloseam useCallback pe funcția de onPress a rândului, dar componenta rândului nu era învelită în React.memo. Rezultatul? Toată lista se reranda oricum la fiecare schimbare de state în părinte. useCallback-ul ăla era absolut degeaba, consuma memorie degeaba.
Regula de aur pe care o aplic acum e simplă: folosești useCallback doar dacă acea componentă copil este memorizată cu React.memo și chiar vrei să previi rerandarea ei. Altfel, lasă funcția inline simplă. E mai curată și nu încarcă garbage collector-ul.
Când chiar merită React.memo?
Meteorologia performanței în React Native se schimbă când vorbim de liste lungi. Dacă ai un item de listă cu imagini, text formatat, poate și ceva animații, acolo vrei React.memo.
Dar atenție la trade-off-ul clasic: compararea prop-urilor (shallow comparison) costă CPU cycles. Dacă prop-urile se schimbă aproape la fiecare randare (de exemplu, un timestamp care se updatează des), React.memo devine o ancoră care trage aplicația în jos. Încearcă să menții obiectele de props cât mai plate (flat). Nu pasa un obiect imens de tip user dacă ai nevoie doar de user.name și user.avatar.
FlatList vs FlashList: Trecerea la nivelul următor
Dacă ai de afișat mai mult de 100-200 de iteme cu layout complex, FlatList pur și simplu își arată limitele. FlatList funcționează prin montarea și demontarea componentelor pe măsură ce dai scroll. Asta pune o presiune imensă pe bridge-ul de React Native și pe garbage collector, generând acele porțiuni albe enervante când dai scroll rapid.
La un proiect de e-commerce, am înlocuit FlatList cu FlashList (librăria celor de la Shopify). Rezultatul? Am sărit de la un chinuit 38 FPS la un 60 FPS stabil pe un dispozitiv Android entry-level de acum 4 ani.
FlashList nu distruge componentele care ies din ecran, ci le reciclează (recyling views). Schimbă doar datele din ele.
Dar vine cu un compromis major: trebuie să îi livrezi un estimatedItemSize extrem de precis. Dacă estimezi greșit dimensiunea medie a unui item, lista va „agăța” vizibil la scroll pentru că trebuie să își recalculeze layout-ul din mers. De asemenea, dacă itemele tale au înălțimi radical diferite, optimizarea oferită de FlashList scade drastic.
Tu ce folosești pentru listele complexe din producție? Ai rămas pe FlatList-ul nativ tunat din props sau ai trecut complet pe FlashList?