Hook useMemo v React Native memoizuje výsledek výpočtů mezi překreslením komponenty a zabraňuje opakovanému provádění nákladných operací. Na rozdíl od useCallback, který memoizuje funkci, useMemo ukládá vrácenou hodnotu a přepočítává ji pouze při změně uvedených závislostí. Podle React Docs, 2024 je memoizace obzvláště účinná pro výpočty s velkými poli a složitými transformacemi dat. V React Native každé další překreslení vytváří dodatečnou zátěž na mostové spojení mezi JavaScript a nativními vlákny, proto správné použití useMemo přímo ovlivňuje plynulost animací a rychlost odezvy rozhraní.
Hlavní body
useMemo — je hook ze standardní knihovny React, dostupný v React Native bez dalších balíčků. Memoizuje hodnotu vrácenou předanou funkcí a tuto hodnotu znovu používá v následujících překresleních, dokud se nezmění závislosti uvedené v poli.
Název hooku pochází z anglického memoization — techniky optimalizace, při které se výsledek nákladné funkce ukládá do mezipaměti. Při opakovaném volání se stejnými argumenty se vrátí uložená hodnota místo přepočítávání.
V kontextu React Native je memoizace obzvláště důležitá kvůli architektuře. Každé překreslení komponenty odesílá data přes most JavaScript — Nativní, což zabírá čas. Pokud komponenta obsahuje nákladné výpočty (filtrování seznamu, řazení, formátování), každé překreslení je bude opakovat, blokovat JS vlákno a způsobovat propady snímků.
Podle React Native Performance Docs, 2024 úzkým hrdlem není nejčastěji vykreslování nativních komponent, ale provádění JavaScript logiky mezi překresleními. useMemo řeší přesně tento problém.
useMemo přijímá funkci a pole závislostí, vrací memoizovanou hodnotu. React ukládá předchozí hodnotu a pole závislostí. Při každém překreslení React porovnává aktuální závislosti s předchozími pomocí Object.is. Pokud se změnila alespoň jedna závislost, funkce se znovu provede a výsledek se uloží.
Signatura useMemo je zcela identická na webu a v React Native. První argument — funkce bez parametrů, vracející memoizovanou hodnotu. Druhý — pole závislostí, při jejichž změně bude hodnota přepočítána.
import React, { useMemo } from 'react';
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
V tomto příkladu se sortedList přepočítává pouze když se změní reference pole items. Pokud se pole změnilo obsahem, ale reference zůstala stejná (mutace), useMemo změny neuvidí — to je důležité omezení.
React používá pro porovnávání závislostí algoritmus Object.is, který funguje podobně jako striktní rovnost ===, ale správně zpracovává NaN (+0 a -0 jsou považovány za odlišné). To znamená, že pro primitivní typy (řetězce, čísla, booleany) porovnání funguje podle hodnoty, a pro objekty a pole — podle reference.
// Object.is({'a': 1}, {'a': 1}) -> false (různé reference)
// Object.is(42, 42) -> true (primitiv podle hodnoty)
// Object.is(NaN, NaN) -> true (správné zpracování NaN)
Pochopení tohoto mechanismu je kritické: pokud předáváte do závislostí nový objekt při každém překreslení, memoizace bude zbytečná, protože závislosti budou považovány za změněné pokaždé.
useMemo je opodstatněný ve třech scénářích: nákladné výpočty, předávání stabilních props potomním komponentám a zachování referenční identity objektů. V React Native se všechny tři scénáře pravidelně vyskytují kvůli specifikům architektury mobilních aplikací.
Pokud komponenta provádí zpracování velkých datových polí (filtrování, řazení, seskupování) nebo výpočetně náročné matematické operace, useMemo zabraňuje opakování těchto výpočtů při každém překreslení. V mobilních aplikacích je typickým příkladem formátování dat z API před zobrazením v seznamu.
Když je potomní komponenta zabalena do React.memo, překresluje se pouze při změně props. Pokud je objekt props vytvářen uvnitř rodiče bez useMemo, při každém překreslení rodiče se vytvoří nová reference a potomní komponenta se překreslí znovu, čímž se ztrácí výhoda React.memo.
V React Native styly často závisí na props — například šířka prvku se vypočítává na základě velikosti obrazovky. useMemo umožňuje vypočítat tyto dynamické styly pouze při změně vstupních parametrů.
useMemo není univerzální optimalizační nástroj. V některých scénářích nepřináší užitek a může dokonce zhoršit výkon kvůli režii ukládání a porovnávání závislostí. V React Native, kde každý bajt paměti hraje roli, je slepé používání useMemo bez měření účinku anti-vzor.
Hook nepřináší užitek ve třech hlavních případech. Zaprvé, pokud je výpočet triviální (jednoduché sčítání, spojování řetězců), náklady useMemo převyšují hodnotu samotného výpočtu. Zadruhé, pokud se závislosti mění při každém překreslení — funkce se stejně provede a memoizace přidá pouze práci navíc. Zatřetí, pokud se komponenta překresluje zřídka, režie ukládání mezipaměti není opodstatněná.
Podle Kent C. Dodds, 2023 je před přidáním useMemo nutné změřit problém pomocí React DevTools Profiler nebo vestavěného Performance Monitor v React Native. Pokud překreslení komponenty trvá méně než 1 ms, memoizace není potřeba.
useMemo a useCallback — dva memoizační hooky z Reactu, které se často zaměňují. Rozdíl spočívá v tom, co ukládají: useMemo vrací výsledek provedení funkce (libovolnou hodnotu), zatímco useCallback vrací samotnou funkci. Oba přijímají pole závislostí, ale syntaxe se liší.
| Vlastnost | useMemo | useCallback |
|---|---|---|
| Vrací | Výsledek provedení funkce | Odkaz na funkci |
| První argument | Funkce vracející hodnotu | Funkce k memoizaci |
| Typické použití | Ukládání výpočtů do mezipaměti | Stabilní callbacky pro potomní komponenty |
| Ekvivalence | useMemo(() => fn, deps) | useCallback(fn, deps) === useMemo(() => fn, deps) |
V praxi je useCallback syntaktický cukr nad useMemo pro případ, kdy je potřeba memoizovat funkci. V React Native se oba hooky používají stejně často: useMemo — pro data (formátovaný text, vypočítané styly), useCallback — pro obsluhy událostí (onPress, onChangeText).
Podívejme se na dva reálné scénáře použití useMemo v React Native aplikacích. První — filtrování seznamu kontaktů podle vyhledávacího dotazu, druhý — výpočet dynamických stylů na základě velikosti obrazovky.
V tomto příkladu useMemo zabraňuje opakovanému filtrování velkého seznamu kontaktů při každém překreslení, pokud se nezměnil ani vyhledávací dotaz, ani zdrojová data.
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}
/>
);
};
Bez useMemo by se filtrování provádělo při každém překreslení, včetně těch způsobených animacemi nebo změnou stavu jiných částí komponenty. S useMemo se filtrování spouští pouze při změně contacts nebo searchQuery.
V React Native styly často závisí na velikosti obrazovky nebo props komponenty. useMemo umožňuje vypočítat takový objekt stylů jednou a znovu jej používat, dokud se závislosti nezmění.
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>
);
};
Tento přístup zaručuje, že objekt cardStyle zůstává stabilní (stejná reference), dokud se isSelected nezmění. Pokud je Card zabalen do React.memo, tento vzor zabraňuje zbytečnému překreslování potomních prvků.
Často kladené otázky
useMemo vrací memoizovanou hodnotu — výsledek provedení funkce předané jako první argument. Při následujících překresleních React vrací uloženou hodnotu, pokud se závislosti nezměnily.
useMemo vrací výsledek provedení funkce (libovolnou hodnotu: číslo, objekt, JSX), zatímco useCallback vrací samotnou funkci. Navíc useCallback(fn, deps) je ekvivalentní useMemo(() => fn, deps).
useMemo je zbytečný při triviálních výpočtech (sčítání, spojování), vzácných překresleních, závislostech měnících se při každém překreslení a pro primitivní typy. Vždy měřte výkon před přidáním useMemo.
Ano, pokud se používá zbytečně. React ukládá předchozí hodnoty do paměti a provádí porovnávání závislostí při každém překreslení. U jednoduchých výpočtů režie těchto operací převyšuje přínos memoizace.
Použijte React DevTools Profiler pro měření času překreslování komponent. V React Native je také k dispozici Performance Monitor přes vývojářskou nabídku. Pokud překreslení trvá méně než 1 ms — useMemo není potřeba.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také