useMemo: какво е, кеширане на изчисления и React Native

Автор: IT Sectr Публикувано: 2026-07-05 Време за четене: 10 мин

Hook-ът useMemo в React Native мемоизира резултата от изчисленията между преизобразяванията на компонента, предотвратявайки повторното изпълнение на скъпи операции. За разлика от useCallback, който мемоизира функцията, useMemo запазва върнатата стойност и я преизчислява само при промяна на посочените зависимости. Според React Docs, 2024, мемоизацията е особено ефективна за изчисления с големи масиви и сложни трансформации на данни. В React Native всяко допълнително преизобразяване създава допълнително натоварване на мостовата връзка между JavaScript и нативните нишки, поради което правилното използване на useMemo пряко влияе върху плавността на анимациите и скоростта на отговор на интерфейса.

Основни точки

  • useMemo — React hook за мемоизация на стойности, който кешира резултата от функция между преизобразяванията
  • Hook-ът приема два аргумента: изчислителна функция и масив от зависимости
  • Стойността се преизчислява само когато поне една зависимост се промени
  • В React Native useMemo е критичен за оптимизиране на производителността на списъци и анимации
  • Злоупотребата с useMemo може да влоши производителността поради разходите за сравняване на зависимости

Какво е useMemo в React Native

useMemo — е hook от стандартната библиотека на React, достъпен в React Native без допълнителни пакети. Той мемоизира стойността, върната от подадената функция, и използва повторно тази стойност в следващите преизобразявания, докато не се променят зависимостите, посочени в масива.

Името на hook-а произлиза от английското memoization — техника за оптимизация, при която резултатът от скъпа функция се съхранява в кеш. При повторно извикване със същите аргументи се връща запазената стойност вместо повторно изчисление.

В контекста на React Native мемоизацията е особено важна поради архитектурата. Всяко преизобразяване на компонента изпраща данни през моста JavaScript — Нативен, което отнема време. Ако компонентът съдържа скъпи изчисления (филтриране на списък, сортиране, форматиране), всяко преизобразяване ще ги повтаря, блокирайки JS нишката и причинявайки падане на кадри.

Според React Native Performance Docs, 2024, тясното място най-често не е изобразяването на нативни компоненти, а изпълнението на JavaScript логика между преизобразяванията. useMemo решава точно този проблем.

Как работи мемоизацията на стойности

useMemo приема функция и масив от зависимости, връщайки мемоизирана стойност. React съхранява предишната стойност и масива от зависимости. При всяко преизобразяване React сравнява текущите зависимости с предишните, използвайки Object.is. Ако поне една зависимост се е променила, функцията се изпълнява отново и резултатът се запазва.

Синтаксис и предаване на аргументи

Подписът на useMemo е напълно идентичен в уеб и в React Native. Първият аргумент — функция без параметри, връщаща мемоизираната стойност. Вторият — масив от зависимости, при промяна на които стойността ще бъде преизчислена.

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

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

В този пример sortedList се преизчислява само когато се промени референцията на масива items. Ако масивът се е променил по съдържание, но референцията е останала същата (мутация), useMemo няма да види промените — това е важно ограничение.

Сравняване на зависимости чрез Object.is

React използва за сравняване на зависимости алгоритъма Object.is, който работи подобно на строгото равенство ===, но обработва правилно NaN (+0 и -0 се считат за различни). Това означава, че за примитивни типове (низове, числа, булеви) сравнението работи по стойност, а за обекти и масиви — по референция.

js
// Object.is({'a': 1}, {'a': 1}) -> false (различни референции)
// Object.is(42, 42) -> true (примитив по стойност)
// Object.is(NaN, NaN) -> true (коректна обработка на NaN)

Разбирането на този механизъм е критично: ако предавате в зависимостите нов обект при всяко преизобразяване, мемоизацията ще бъде безполезна, тъй като зависимостите ще се считат за променени всеки път.

Кога да използваме useMemo

useMemo е оправдан в три сценария: скъпи изчисления, предаване на стабилни props на дъщерни компоненти и запазване на референтната идентичност на обекти. В React Native и трите сценария се срещат редовно поради спецификата на архитектурата на мобилните приложения.

Скъпи изчисления

Ако компонентът извършва обработка на големи масиви от данни (филтриране, сортиране, групиране) или ресурсоемки математически операции, useMemo предотвратява повторението на тези изчисления при всяко преизобразяване. В мобилните приложения типичен пример е форматирането на данни от API преди показване в списък.

Стабилни props за дъщерни компоненти

Когато дъщерният компонент е увит в React.memo, той се преизобразява само при промяна на props. Ако обектът props се създава вътре в родителя без useMemo, при всяко преизобразяване на родителя ще се създава нова референция и дъщерният компонент ще се преизобразява отново, анулирайки ползата от React.memo.

Мемоизация на изчисления на стилове

В React Native стиловете често зависят от props — например ширината на елемент се изчислява на базата на размера на екрана. useMemo позволява изчисляването на тези динамични стилове само при промяна на входните параметри.

Кога useMemo е безполезен

useMemo не е универсално средство за оптимизация. В определени сценарии той не носи полза и дори може да влоши производителността поради допълнителните разходи за съхраняване и сравняване на зависимости. В React Native, където всеки байт памет е важен, сляпото прилагане на useMemo без измерване на ефекта е анти-модел.

Hook-ът не носи полза в три основни случая. Първо, ако изчислението е тривиално (просто събиране, конкатенация на низове), разходите за useMemo надвишават стойността на самото изчисление. Второ, ако зависимостите се променят при всяко преизобразяване — функцията така или иначе ще се изпълни, а мемоизацията ще добави само допълнителна работа. Трето, ако компонентът се преизобразява рядко, допълнителният разход за съхраняване на кеш не е оправдан.

Според Kent C. Dodds, 2023, преди да добавите useMemo, трябва да измерите проблема с помощта на React DevTools Profiler или вградения Performance Monitor в React Native. Ако преизобразяването на компонента отнема по-малко от 1 ms, мемоизацията не е необходима.

  • Тривиални изчисления — събиране, конкатенация, прости тернарни операции
  • Редки преизобразявания — статични екрани, които се преизобразяват веднъж
  • Променящи се зависимости — ако зависимостите са нови при всяко преизобразяване, мемоизацията е безполезна
  • Примитивни стойности — числата и низовете не се нуждаят от мемоизация, те така или иначе са евтини

useMemo и useCallback: сравнение

useMemo и useCallback — два hook-а за мемоизация от React, които често се бъркат. Разликата е в това какво съхраняват: useMemo връща резултата от изпълнението на функцията (произволна стойност), докато useCallback връща самата функция. И двата приемат масив от зависимости, но синтаксисът се различава.

ХарактеристикаuseMemouseCallback
ВръщаРезултат от изпълнение на функцияРеференция към функцията
Първи аргументФункция, връщаща стойностФункция за мемоизация
Типично приложениеКеширане на изчисленияСтабилни callback-и за дъщерни компоненти
ЕквивалентностuseMemo(() => fn, deps)useCallback(fn, deps) === useMemo(() => fn, deps)

На практика useCallback е синтактична захар над useMemo за случая, когато трябва да се мемоизира функция. В React Native и двата hook-а се използват еднакво често: useMemo — за данни (форматиран текст, изчислени стилове), useCallback — за обработчици на събития (onPress, onChangeText).

Практически примери с useMemo

Нека разгледаме два реални сценария за използване на useMemo в React Native приложения. Първият — филтриране на списък с контакти по заявка за търсене, вторият — изчисляване на динамични стилове на базата на размера на екрана.

Пример 1: търсене и филтриране на списък

В този пример useMemo предотвратява повторното филтриране на голям списък с контакти при всяко преизобразяване, ако нито заявката за търсене, нито изходните данни са се променили.

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

Без useMemo филтрирането ще се изпълнява при всяко преизобразяване, включително тези, причинени от анимации или промяна на състоянието на други части на компонента. С useMemo филтрирането се задейства само при промяна на contacts или searchQuery.

Пример 2: изчисляване на динамични стилове

В React Native стиловете често зависят от размерите на екрана или props на компонента. useMemo позволява изчисляването на такъв обект от стилове веднъж и повторното му използване, докато зависимостите не се променят.

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

Този подход гарантира, че обектът cardStyle остава стабилен (същата референция), докато isSelected не се промени. Ако Card е увит в React.memo, този модел предотвратява ненужни преизобразявания на дъщерни елементи.

Често задавани въпроси

Какво връща useMemo?

useMemo връща мемоизираната стойност — резултатът от изпълнението на функцията, подадена като първи аргумент. При следващи преизобразявания React връща запазената стойност, ако зависимостите не са се променили.

По какво useMemo се различава от useCallback?

useMemo връща резултата от изпълнението на функцията (произволна стойност: число, обект, JSX), докато useCallback връща самата функция. Освен това useCallback(fn, deps) е еквивалентен на useMemo(() => fn, deps).

Кога useMemo не е необходим?

useMemo е безполезен при тривиални изчисления (събиране, конкатенация), редки преизобразявания, променящи се при всяко преизобразяване зависимости и за примитивни типове. Винаги измервайте производителността преди добавяне на useMemo.

Може ли useMemo да влоши производителността?

Да, ако се използва без необходимост. React съхранява предишните стойности в паметта и извършва сравнение на зависимости при всяко преизобразяване. За прости изчисления допълнителният разход за тези операции надвишава ползата от мемоизацията.

Как да дебъгваме работата на useMemo?

Използвайте React DevTools Profiler за измерване на времето за преизобразяване на компоненти. В React Native също е наличен Performance Monitor чрез менюто за разработчици. Ако преизобразяването отнема по-малко от 1 ms — useMemo не е необходим.

Обобщение

  • useMemo — React hook за мемоизация на стойности, който кешира резултата от функция между преизобразяванията
  • Hook-ът приема изчислителна функция и масив от зависимости, преизчислявайки стойността само при тяхната промяна
  • В React Native useMemo е особено важен за оптимизиране на списъци, анимации и сложни изчисления
  • Ключови сценарии: скъпи изчисления, стабилни props за React.memo, динамични стилове
  • useMemo се различава от useCallback: първият връща стойност, вторият — функция
  • Злоупотребата с useMemo влошава производителността поради допълнителния разход за съхраняване и сравняване на зависимости
  • Преди добавяне на useMemo винаги измервайте проблема чрез React DevTools Profiler или Performance Monitor в React Native

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също