useMemo: czym jest, buforowanie obliczeń i React Native

Autor: IT Sectr Opublikowano: 2026-07-05 Czas czytania: 10 min

Hook useMemo w React Native memoizuje wynik obliczeń między renderami komponentu, zapobiegając ponownemu wykonywaniu kosztownych operacji. W przeciwieństwie do useCallback, który memoizuje funkcję, useMemo zachowuje zwracaną wartość i przelicza ją tylko przy zmianie wskazanych zależności. Według React Docs, 2024, memoizacja jest szczególnie efektywna dla obliczeń na dużych tablicach i złożonych transformacji danych. W React Native każde dodatkowe przerenderowanie tworzy obciążenie dla połączenia mostkowego między JavaScript a natywnymi wątkami, dlatego prawidłowe użycie useMemo bezpośrednio wpływa na płynność animacji i szybkość reakcji interfejsu.

Najważniejsze

  • useMemo — hook React do memoizacji wartości, który zapamiętuje wynik funkcji między renderami
  • Hook przyjmuje dwa argumenty: funkcję obliczeniową i tablicę zależności
  • Wartość jest przeliczana tylko gdy zmieni się przynajmniej jedna zależność
  • W React Native useMemo jest krytyczny dla optymalizacji wydajności list i animacji
  • Nadużywanie useMemo może pogorszyć wydajność z powodu kosztów porównywania zależności

Czym jest useMemo w React Native

useMemo — to hook ze standardowej biblioteki React, dostępny w React Native bez dodatkowych pakietów. Memoizuje wartość zwracaną przez przekazaną funkcję i ponownie używa tej wartości w kolejnych renderach, dopóki nie zmienią się wskazane w tablicy zależności.

Nazwa hooka pochodzi od angielskiego memoization — techniki optymalizacji, w której wynik kosztownej funkcji jest przechowywany w pamięci podręcznej. Przy ponownym wywołaniu z tymi samymi argumentami zwracana jest zapamiętana wartość zamiast ponownego obliczania.

W kontekście React Native memoizacja jest szczególnie ważna ze względu na architekturę. Każdy przerenderowanie komponentu wysyła dane przez most JavaScript — Natywny, co zajmuje czas. Jeśli komponent zawiera kosztowne obliczenia (filtrowanie listy, sortowanie, formatowanie), każde przerenderowanie będzie je powtarzać, blokując wątek JS i powodując spadki klatek.

Według React Native Performance Docs, 2024, wąskim gardłem najczęściej nie jest renderowanie natywnych komponentów, ale wykonanie logiki JavaScript między renderami. useMemo rozwiązuje właśnie ten problem.

Jak działa memoizacja wartości

useMemo przyjmuje funkcję i tablicę zależności, zwracając zmemoizowaną wartość. React przechowuje poprzednią wartość i tablicę zależności. Przy każdym renderze React porównuje bieżące zależności z poprzednimi za pomocą Object.is. Jeśli zmieniła się przynajmniej jedna zależność, funkcja jest wykonywana ponownie, a wynik zapisywany.

Składnia i przekazywanie argumentów

Sygnatura useMemo jest całkowicie identyczna w wersji webowej i w React Native. Pierwszy argument — funkcja bez parametrów, zwracająca memoizowaną wartość. Drugi — tablica zależności, przy zmianie których wartość zostanie przeliczona.

js
import React, { useMemo } from 'react';

const sortedList = useMemo(() => {
    return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);

W tym przykładzie sortedList jest przeliczana tylko gdy zmienia się referencja do tablicy items. Jeśli tablica zmieniła zawartość, ale referencja pozostała ta sama (mutacja), useMemo nie zauważy zmian — to ważne ograniczenie.

Porównywanie zależności przez Object.is

React używa do porównywania zależności algorytmu Object.is, który działa podobnie do ścisłej równości ===, ale poprawnie obsługuje NaN (+0 i -0 są uznawane za różne). Oznacza to, że dla typów prymitywnych (łańcuchy, liczby, boolean) porównanie działa według wartości, a dla obiektów i tablic — według referencji.

js
// Object.is({'a': 1}, {'a': 1}) -> false (różne referencje)
// Object.is(42, 42) -> true (typ prymitywny według wartości)
// Object.is(NaN, NaN) -> true (poprawna obsługa NaN)

Zrozumienie tego mechanizmu jest krytyczne: jeśli przekazujesz w zależnościach nowy obiekt przy każdym renderze, memoizacja będzie bezużyteczna, ponieważ zależności będą uznawane za zmienione za każdym razem.

Kiedy używać useMemo

useMemo jest uzasadniony w trzech scenariuszach: kosztowne obliczenia, przekazywanie stabilnych propsów do komponentów potomnych oraz zachowanie tożsamości referencyjnej obiektów. W React Native wszystkie trzy scenariusze występują regularnie ze względu na specyfikę architektury aplikacji mobilnych.

Kosztowne obliczenia

Jeśli komponent wykonuje przetwarzanie dużych tablic danych (filtrowanie, sortowanie, grupowanie) lub zasobożerne operacje matematyczne, useMemo zapobiega powtarzaniu tych obliczeń przy każdym przerenderowaniu. W aplikacjach mobilnych typowym przykładem jest formatowanie danych z API przed wyświetleniem na liście.

Stabilne propsy dla komponentów potomnych

Gdy komponent potomny jest owinięty w React.memo, przerenderowuje się tylko przy zmianie propsów. Jeśli obiekt propsa jest tworzony wewnątrz rodzica bez useMemo, przy każdym renderze rodzica będzie tworzona nowa referencja, a komponent potomny będzie renderowany od nowa, niwelując korzyści z React.memo.

Memoizacja obliczeń stylów

W React Native style często zależą od propsów — na przykład szerokość elementu jest obliczana na podstawie rozmiaru ekranu. useMemo pozwala obliczać takie dynamiczne style tylko przy zmianie parametrów wejściowych.

Kiedy useMemo jest bezużyteczny

useMemo nie jest uniwersalnym środkiem optymalizacji. W wielu scenariuszach nie daje zysku, a nawet może pogorszyć wydajność z powodu narzutu na przechowywanie i porównywanie zależności. W React Native, gdzie każdy bajt pamięci jest ważny, ślepe stosowanie useMemo bez pomiaru efektu jest antywzorem.

Hook nie przynosi korzyści w trzech głównych przypadkach. Po pierwsze, jeśli obliczenie jest trywialne (proste dodawanie, konkatenacja łańcuchów), koszty useMemo przewyższają koszt samego obliczenia. Po drugie, jeśli zależności zmieniają się przy każdym renderze — funkcja i tak będzie wykonywana, a memoizacja doda tylko dodatkową pracę. Po trzecie, jeśli komponent renderuje się rzadko, narzut na przechowywanie pamięci podręcznej nie jest uzasadniony.

Według Kent C. Dodds, 2023, przed dodaniem useMemo należy zmierzyć problem za pomocą React DevTools Profiler lub wbudowanego Performance Monitor w React Native. Jeśli przerenderowanie komponentu zajmuje mniej niż 1 ms, memoizacja nie jest potrzebna.

  • Trywialne obliczenia — dodawanie, konkatenacja, proste operacje ternary
  • Rzadkie przerenderowania — statyczne ekrany, które renderują się raz
  • Zmieniające się zależności — jeśli zależności są nowe przy każdym renderze, memoizacja jest bezużyteczna
  • Wartości prymitywne — liczby i łańcuchy nie wymagają memoizacji, są i tak tanie

useMemo i useCallback: porównanie

useMemo i useCallback — dwa hooki memoizacji z React, które często są mylone. Różnica polega na tym, co dokładnie przechowują: useMemo zwraca wynik wykonania funkcji (dowolną wartość), a useCallback zwraca samą funkcję. Oba przyjmują tablicę zależności, ale składnia się różni.

CechauseMemouseCallback
ZwracaWynik wykonania funkcjiReferencję do funkcji
Pierwszy argumentFunkcja zwracająca wartośćFunkcja do zmemoizowania
Typowe zastosowanieZapamiętywanie obliczeńStabilne callbacki dla komponentów potomnych
RównoważnośćuseMemo(() => fn, deps)useCallback(fn, deps) === useMemo(() => fn, deps)

W praktyce useCallback to cukier składniowy nad useMemo dla przypadku, gdy trzeba zmemoizować funkcję. W React Native oba hooki są używane równie często: useMemo — dla danych (sformatowany tekst, obliczone style), useCallback — dla handlerów zdarzeń (onPress, onChangeText).

Praktyczne przykłady z useMemo

Rozważmy dwa rzeczywiste scenariusze użycia useMemo w aplikacjach React Native. Pierwszy — filtrowanie listy kontaktów według zapytania wyszukiwania, drugi — obliczanie dynamicznych stylów na podstawie rozmiaru ekranu.

Przykład 1: wyszukiwanie i filtrowanie listy

W tym przykładzie useMemo zapobiega ponownemu filtrowaniu dużej listy kontaktów przy każdym renderze, jeśli nie zmieniło się ani zapytanie wyszukiwania, ani źródłowe dane.

js
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 filtrowanie byłoby wykonywane przy każdym renderze, włączając te wywołane przez animacje lub zmianę stanu innych części komponentu. Z useMemo filtrowanie uruchamia się tylko przy zmianie contacts lub searchQuery.

Przykład 2: obliczanie dynamicznych stylów

W React Native style często zależą od rozmiarów ekranu lub propsów komponentu. useMemo pozwala obliczać taki obiekt stylów raz i ponownie go używać, dopóki zależności się nie zmienią.

js
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>
    );
};

To podejście gwarantuje, że obiekt cardStyle pozostaje stabilny (ta sama referencja), dopóki isSelected się nie zmieni. Jeśli Card jest owinięty w React.memo, taki wzorzec zapobiega niepotrzebnym przerenderowaniom elementów potomnych.

Często zadawane pytania

Co zwraca useMemo?

useMemo zwraca zmemoizowaną wartość — wynik wykonania funkcji przekazanej jako pierwszy argument. Przy kolejnych renderach React zwraca zapamiętaną wartość, jeśli zależności się nie zmieniły.

Czym useMemo różni się od useCallback?

useMemo zwraca wynik wykonania funkcji (dowolną wartość: liczbę, obiekt, JSX), a useCallback zwraca samą funkcję. Przy czym useCallback(fn, deps) jest równoważne useMemo(() => fn, deps).

Kiedy useMemo nie jest potrzebny?

useMemo jest bezużyteczny przy trywialnych obliczeniach (dodawanie, konkatenacja), rzadkich przerenderowaniach, zmieniających się przy każdym renderze zależnościach i dla typów prymitywnych. Zawsze mierz wydajność przed dodaniem useMemo.

Czy useMemo może pogorszyć wydajność?

Tak, jeśli używać go bez potrzeby. React przechowuje poprzednie wartości w pamięci i wykonuje porównanie zależności przy każdym renderze. Dla prostych obliczeń narzut tych operacji przewyższa zysk z memoizacji.

Jak debugować działanie useMemo?

Użyj React DevTools Profiler do pomiaru czasu renderowania komponentów. W React Native dostępny jest również Performance Monitor przez menu deweloperskie. Jeśli renderowanie zajmuje mniej niż 1 ms — useMemo nie jest potrzebny.

Podsumowanie

  • useMemo — hook React do memoizacji wartości, zapamiętujący wynik funkcji między renderami
  • Hook przyjmuje funkcję obliczeniową i tablicę zależności, przeliczając wartość tylko przy ich zmianie
  • W React Native useMemo jest szczególnie ważny dla optymalizacji list, animacji i złożonych obliczeń
  • Kluczowe scenariusze: kosztowne obliczenia, stabilne propsy dla React.memo, dynamiczne style
  • useMemo różni się od useCallback: pierwszy zwraca wartość, drugi — funkcję
  • Nadużywanie useMemo pogarsza wydajność z powodu narzutu na przechowywanie i porównywanie zależności
  • Przed dodaniem useMemo zawsze mierz problem przez React DevTools Profiler lub Performance Monitor w React Native

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również