Хук useMemo у React Native мемоизира резултат прорачуна између рендеровања компоненте, спречавајући поновно извршавање скупих операција. За разлику од useCallback-а, који мемоизира функцију, useMemo чува повратну вредност и поново је израчунава само када се промене наведене зависности. Према React Docs, 2024, мемоизација је посебно ефикасна за прорачуне са великим низовима и сложене трансформације података. У React Native свако додатно поновно рендеровање ствара додатно оптерећење на мостној вези између JavaScript и матичних нити, тако да правилна употреба useMemo-а директно утиче на глаткоћу анимација и брзину одзива интерфејса.
Главне тачке
useMemo — је хук из стандардне React библиотеке, доступан у React Native без додатних пакета. Он мемоизира вредност коју враћа прослеђена функција и поново користи ту вредност у наредним рендеровањима све док се не промене зависности наведене у низу.
Име хука потиче од енглеског memoization — технике оптимизације при којој се резултат скупе функције чува у кешу. При поновном позиву са истим аргументима враћа се сачувана вредност уместо поновног израчунавања.
У контексту React Native, мемоизација је посебно важна због архитектуре. Свако поновно рендеровање компоненте шаље податке кроз мост JavaScript — Матични, што захтева време. Ако компонента садржи скупе прорачуне (филтрирање листе, сортирање, форматирање), свако поновно рендеровање ће их понављати, блокирајући JS нит и изазивајући пад фрејмова.
Према React Native Performance Docs, 2024, уско грло најчешће није рендеровање матичних компоненти, већ извршавање JavaScript логике између рендеровања. useMemo решава управо овај проблем.
useMemo прихвата функцију и низ зависности, враћајући мемоизовану вредност. React чува претходну вредност и низ зависности. При сваком рендеровању React пореди тренутне зависности са претходним користећи Object.is. Ако се променила бар једна зависност, функција се поново извршава и резултат се чува.
Потпис useMemo-а је потпуно идентичан на вебу и у React Native. Први аргумент — функција без параметара, која враћа вредност за мемоизацију. Други — низ зависности, при чијој промени ће вредност бити поново израчуната.
import React, { useMemo } from 'react';
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
У овом примеру sortedList се поново израчунава само када се промени референца низа items. Ако се низ променио по садржају, али је референца остала иста (мутација), useMemo неће видети промене — ово је важно ограничење.
React користи за поређење зависности алгоритам Object.is, који ради слично строгој једнакости ===, али исправно рукује NaN (+0 и -0 се сматрају различитим). То значи да за примитивне типове (стрингови, бројеви, булови) поређење ради по вредности, а за објекте и низове — по референци.
// Object.is({'a': 1}, {'a': 1}) -> false (различите референце)
// Object.is(42, 42) -> true (примитив по вредности)
// Object.is(NaN, NaN) -> true (исправно руковање NaN-ом)
Разумевање овог механизма је кључно: ако прослеђујете у зависности нови објекат при сваком рендеровању, мемоизација ће бити бескорисна, јер ће се зависности сматрати промењеним сваки пут.
useMemo је оправдан у три сценарија: скупи прорачуни, прослеђивање стабилних пропсова компонентама деце и очување референцијалног идентитета објеката. У React Native се сва три сценарија редовно јављају због специфичности архитектуре мобилних апликација.
Ако компонента врши обраду великих низова података (филтрирање, сортирање, груписање) или ресурсно захтевне математичке операције, useMemo спречава понављање ових прорачуна при сваком поновном рендеровању. У мобилним апликацијама типичан пример је форматирање података из API-ја пре приказа у листи.
Када је компонента дете омотана у React.memo, она се поново рендерује само при промени пропсова. Ако се пропс објекат креира унутар родитеља без useMemo-а, при сваком рендеровању родитеља ће се креирати нова референца, а компонента дете ће се рендеровати изнова, поништавајући предност React.memo-а.
У React Native стилови често зависе од пропсова — на пример, ширина елемента се израчунава на основу величине екрана. useMemo омогућава израчунавање ових динамичких стилова само при промени улазних параметара.
useMemo није универзално средство оптимизације. У одређеним сценаријима не доноси добит и чак може погоршати перформансе због додатних трошкова чувања и поређења зависности. У React Native, где је сваки бајт меморије битан, слепа примена useMemo-а без мерења ефекта је антиобразац.
Хук не доноси корист у три главна случаја. Прво, ако је прорачун тривијалан (просто сабирање, конкатенација стрингова), трошкови useMemo-а премашују вредност самог прорачуна. Друго, ако се зависности мењају при сваком рендеровању — функција ће се ипак извршавати, а мемоизација ће додати само додатни посао. Треће, ако се компонента ретко рендерује, трошак чувања кеша није оправдан.
Према Kent C. Dodds, 2023, пре додавања useMemo-а потребно је измерити проблем помоћу React DevTools Profiler-а или уграђеног Performance Monitor-а у React Native. Ако поновно рендеровање компоненте траје мање од 1 ms, мемоизација није потребна.
useMemo и useCallback — два хука мемоизације из React-а која се често мешају. Разлика је у томе шта чувају: useMemo враћа резултат извршавања функције (било коју вредност), а useCallback враћа саму функцију. Оба прихватају низ зависности, али синтакса се разликује.
| Карактеристика | useMemo | useCallback |
|---|---|---|
| Враћа | Резултат извршавања функције | Референцу на функцију |
| Први аргумент | Функција која враћа вредност | Функција за мемоизацију |
| Типична примена | Кеширање прорачуна | Стабилни колбекови за компоненте деце |
| Еквивалентност | useMemo(() => fn, deps) | useCallback(fn, deps) === useMemo(() => fn, deps) |
У пракси, useCallback је синтаксни шећер над useMemo-ом за случај када је потребно мемоизовати функцију. У React Native се оба хука користе подједнако често: useMemo — за податке (форматиран текст, израчунати стилови), useCallback — за руковаоце догађајима (onPress, onChangeText).
Размотримо два стварна сценарија коришћења useMemo-а у React Native апликацијама. Први — филтрирање листе контаката по упиту претраге, други — израчунавање динамичких стилова на основу величине екрана.
У овом примеру useMemo спречава поновно филтрирање велике листе контаката при сваком рендеровању, ако се нису променили ни упит претраге ни изворни подаци.
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}
/>
);
};
Без useMemo-а, филтрирање би се извршавало при сваком рендеровању, укључујући она изазвана анимацијама или променом стања других делова компоненте. Са useMemo-ом, филтрирање се покреће само при промени contacts или searchQuery.
У React Native стилови често зависе од величина екрана или пропсова компоненте. useMemo омогућава израчунавање таквог објекта стилова једном и поновно коришћење док се зависности не промене.
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>
);
};
Овај приступ гарантује да објекат cardStyle остаје стабилан (иста референца) док се isSelected не промени. Ако је Card омотан у React.memo, овај образац спречава непотребна поновна рендеровања елемената деце.
Често постављана питања
useMemo враћа мемоизовану вредност — резултат извршавања функције прослеђене као први аргумент. При наредним рендеровањима React враћа сачувану вредност ако се зависности нису промениле.
useMemo враћа резултат извршавања функције (било коју вредност: број, објекат, JSX), а useCallback враћа саму функцију. Притом је useCallback(fn, deps) еквивалентан useMemo(() => fn, deps).
useMemo је бескористан код тривијалних прорачуна (сабирање, конкатенација), ретких поновних рендеровања, зависности које се мењају при сваком рендеровању и за примитивне типове. Увек мерите перформансе пре додавања useMemo-а.
Да, ако се користи без потребе. React чува претходне вредности у меморији и врши поређење зависности при сваком рендеровању. За једноставне прорачуне трошак ових операција премашује добит од мемоизације.
Користите React DevTools Profiler за мерење времена рендеровања компоненти. У React Native је такође доступан Performance Monitor преко менија за програмере. Ако поновно рендеровање траје мање од 1 ms — useMemo није потребан.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође