Hook-ul useMemo din React Native memoizează rezultatul calculelor între randările componentei, prevenind executarea repetată a operațiilor costisitoare. Spre deosebire de useCallback, care memoizează funcția, useMemo păstrează valoarea returnată și o recalculează doar la modificarea dependințelor specificate. Conform React Docs, 2024, memoizarea este deosebit de eficientă pentru calcule cu tablouri mari și transformări complexe de date. În React Native, fiecare re-renderizare suplimentară creează o sarcină suplimentară pe conexiunea punte dintre firele JavaScript și native, astfel că utilizarea corectă a useMemo influențează direct fluența animațiilor și viteza de răspuns a interfeței.
Puncte cheie
useMemo — este un hook din biblioteca standard React, disponibil în React Native fără pachete suplimentare. Acesta memoizează valoarea returnată de funcția transmisă și reutilizează această valoare în randările ulterioare până când dependințele specificate în tablou se modifică.
Numele hook-ului provine din englezescul memoization — o tehnică de optimizare prin care rezultatul unei funcții costisitoare este stocat în cache. La apelul repetat cu aceleași argumente, se returnează valoarea salvată în locul recalculării.
În contextul React Native, memoizarea este deosebit de importantă datorită arhitecturii specifice. Fiecare re-renderizare a componentei trimite date prin puntea JavaScript — Nativo, ceea ce consumă timp. Dacă componenta conține calcule costisitoare (filtrarea listei, sortare, formatare), fiecare re-renderizare le va repeta, blocând firul JS și cauzând căderi de cadre.
Conform React Native Performance Docs, 2024, blocajul cel mai frecvent nu este randarea componentelor native, ci execuția logicii JavaScript între randări. useMemo rezolvă exact această problemă.
useMemo primește o funcție și un tablou de dependințe, returnând o valoare memoizată. React stochează valoarea anterioară și tabloul de dependințe. La fiecare randare, React compară dependințele curente cu cele anterioare folosind Object.is. Dacă cel puțin o dependință s-a modificat, funcția se execută din nou, iar rezultatul este salvat.
Semnătura useMemo este complet identică în web și în React Native. Primul argument — o funcție fără parametri, care returnează valoarea de memoizat. Al doilea — tabloul de dependințe, la modificarea cărora valoarea va fi recalculată.
import React, { useMemo } from 'react';
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
În acest exemplu, sortedList se recalculează doar când se modifică referința tabloului items. Dacă tabloul s-a modificat ca conținut, dar referința a rămas aceeași (mutație), useMemo nu va observa schimbările — aceasta este o limitare importantă.
React folosește pentru compararea dependințelor algoritmul Object.is, care funcționează similar cu egalitatea strictă ===, dar gestionează corect NaN (+0 și -0 sunt considerate diferite). Aceasta înseamnă că pentru tipurile primitive (șiruri, numere, booleeni) compararea funcționează după valoare, iar pentru obiecte și tablouri — după referință.
// Object.is({'a': 1}, {'a': 1}) -> false (referințe diferite)
// Object.is(42, 42) -> true (primitiv după valoare)
// Object.is(NaN, NaN) -> true (gestionarea corectă a NaN)
Înțelegerea acestui mecanism este critică: dacă transmiți în dependințe un obiect nou la fiecare randare, memoizarea va fi inutilă, deoarece dependințele vor fi considerate modificate de fiecare dată.
useMemo este justificat în trei scenarii: calcule costisitoare, transmiterea de props-uri stabile către componentele copil și păstrarea identității referențiale a obiectelor. În React Native, toate trei scenariile apar regulat datorită specificului arhitecturii aplicațiilor mobile.
Dacă componenta execută procesarea tablourilor mari de date (filtrare, sortare, grupare) sau operații matematice consumatoare de resurse, useMemo previne repetarea acestor calcule la fiecare re-renderizare. În aplicațiile mobile, un exemplu tipic este formatarea datelor din API înainte de afișarea în listă.
Când componenta copil este înfășurată în React.memo, aceasta se re-renderizează doar la modificarea props-urilor. Dacă obiectul props este creat în interiorul părintelui fără useMemo, la fiecare randare a părintelui se va crea o nouă referință, iar componenta copil se va randai din nou, anulând beneficiul React.memo.
În React Native, stilurile depind adesea de props-uri — de exemplu, lățimea unui element se calculează pe baza dimensiunii ecranului. useMemo permite calcularea acestor stiluri dinamice doar la modificarea parametrilor de intrare.
useMemo nu este un mijloc universal de optimizare. În unele scenarii, nu aduce beneficii și poate chiar înrăutăți performanța din cauza cheltuielilor suplimentare de stocare și comparare a dependințelor. În React Native, unde fiecare octet de memorie contează, utilizarea oarbă a useMemo fără măsurarea efectului este un anti-pattern.
Hook-ul nu aduce beneficii în trei cazuri principale. În primul rând, dacă calculul este trivial (adunare simplă, concatenare de șiruri), costurile useMemo depășesc valoarea calculului în sine. În al doilea rând, dacă dependințele se schimbă la fiecare randare — funcția se va executa oricum, iar memoizarea va adăuga doar muncă suplimentară. În al treilea rând, dacă componenta se randaează rar, cheltuiala de stocare a cache-ului nu este justificată.
Conform Kent C. Dodds, 2023, înainte de a adăuga useMemo, trebuie să măsori problema cu ajutorul React DevTools Profiler sau al Performance Monitor încorporat în React Native. Dacă re-renderizarea componentei durează mai puțin de 1 ms, memoizarea nu este necesară.
useMemo și useCallback — două hook-uri de memoizare din React care sunt adesea confundate. Diferența constă în ceea ce păstrează: useMemo returnează rezultatul executării funcției (orice valoare), iar useCallback returnează funcția însăși. Ambele primesc un tablou de dependințe, dar sintaxa diferă.
| Caracteristică | useMemo | useCallback |
|---|---|---|
| Returnează | Rezultatul executării funcției | Referința la funcție |
| Primul argument | Funcția care returnează valoarea | Funcția de memoizat |
| Utilizare tipică | Memorarea în cache a calculelor | Callback-uri stabile pentru componentele copil |
| Echivalență | useMemo(() => fn, deps) | useCallback(fn, deps) === useMemo(() => fn, deps) |
În practică, useCallback este zahăr sintactic peste useMemo pentru cazul când trebuie memoizată o funcție. În React Native, ambele hook-uri se folosesc la fel de des: useMemo — pentru date (text formatat, stiluri calculate), useCallback — pentru handler-e de evenimente (onPress, onChangeText).
Să analizăm două scenarii reale de utilizare a useMemo în aplicațiile React Native. Primul — filtrarea listei de contacte după interogarea de căutare, al doilea — calcularea stilurilor dinamice pe baza dimensiunii ecranului.
În acest exemplu, useMemo previne re-filtrarea listei mari de contacte la fiecare randare, dacă nu s-au modificat nici interogarea de căutare, nici datele sursă.
const ContactList = ({ contacts, searchQuery }) => {
const filteredContacts = useMemo(() => {
if (!searchQuery.trim()) return contacts;
const query = searchQuery.toLowerCase();
return contacts.filter((c) =>
c.name.toLowerCase().includes(query) ||
c.phone.includes(query)
);
}, [contacts, searchQuery]);
return (
<FlatList
data={filteredContacts}
renderItem={renderContact}
keyExtractor={(item) => item.id}
/>
);
};
Fără useMemo, filtrarea s-ar executa la fiecare randare, inclusiv cele cauzate de animații sau modificări de stare ale altor părți ale componentei. Cu useMemo, filtrarea se declanșează doar la modificarea contacts sau searchQuery.
În React Native, stilurile depind adesea de dimensiunile ecranului sau de props-urile componentei. useMemo permite calcularea unui astfel de obiect de stiluri o singură dată și reutilizarea lui până când dependințele se modifică.
const Card = ({ title, isSelected }) => {
const cardStyle = useMemo(() => ({
backgroundColor: isSelected ? '#e3f2fd' : '#ffffff',
borderWidth: isSelected ? 2 : 1,
padding: 16,
}), [isSelected]);
return (
<View style={cardStyle}>
<Text>{title}</Text>
</View>
);
};
Această abordare garantează că obiectul cardStyle rămâne stabil (aceeași referință) până când isSelected se modifică. Dacă Card este înfășurat în React.memo, acest model previne re-renderizările inutile ale elementelor copil.
Întrebări frecvente
useMemo returnează valoarea memoizată — rezultatul executării funcției transmise ca prim argument. La randările ulterioare, React returnează valoarea salvată dacă dependințele nu s-au modificat.
useMemo returnează rezultatul executării funcției (orice valoare: număr, obiect, JSX), iar useCallback returnează funcția însăși. În plus, useCallback(fn, deps) este echivalent cu useMemo(() => fn, deps).
useMemo este inutil la calcule trivia (adunare, concatenare), re-renderizări rare, dependințe care se schimbă la fiecare randare și pentru tipurile primitive. Măsoară întotdeauna performanța înainte de a adăuga useMemo.
Da, dacă este folosit fără necesitate. React stochează valorile anterioare în memorie și execută compararea dependințelor la fiecare randare. Pentru calcule simple, cheltuiala acestor operații depășește beneficiul memoizării.
Folosește React DevTools Profiler pentru măsurarea timpului de randare a componentelor. În React Native, este disponibil și Performance Monitor prin meniul de dezvoltator. Dacă re-renderizarea durează mai puțin de 1 ms — useMemo nu este necesar.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și