ГлавнаяБлогuseMemo и useCallback: что реально происходит под капотом
Алгоритмы

useMemo и useCallback: что реально происходит под капотом

Разбираем, чем useMemo и useCallback отличаются, когда они бесполезны, и как избежать частых ошибок. Практические советы для React-разработчиков.

Al
Редакция Algolitalgolit.ru
5 мин чтения18 августа 2026 г.

useMemo и useCallback: что реально происходит под капотом

Многие React-разработчики запоминают синтаксис useMemo и useCallback, но не понимают, что именно они делают. Это приводит к багам и лишним ререндерам. Сегодня разберем, чем эти хуки отличаются, когда они бесполезны, и как избежать типичных ошибок. Готовы? Поехали.

1. useMemo и useCallback решают разные задачи

Многие думают, что это взаимозаменяемые хуки для ускорения. На самом деле:

  • useMemo кэширует вычисленное значение.
  • useCallback кэширует ссылку на функцию.

По сути, useCallback(fn, deps) — это синтаксический сахар для useMemo(() => fn, deps). Разница лишь в том, что useCallback возвращает саму функцию, а useMemo — результат её вызова.

Пример

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]);

В первом случае кэшируется результат вычислений, во втором — сама функция.

2. Ни тот, ни другой не ускоряет код по умолчанию

Оборачивание в useMemo тоже имеет стоимость: на каждом рендере выполняется сравнение зависимостей. Если вычисления внутри дешёвые, вы платите больше, чем экономите. Используйте эти хуки только когда вычисления действительно дорогие, или когда нужно сохранить ссылку (см. пункт 3), а не как рефлекс на каждое производное значение.

Пример

const total = useMemo(() => a + b, [a, b]); // избыточно: сложение дешёвое
const filteredList = useMemo(() => list.filter(isValid), [list]); // оправдано, если list большой

3. Настоящая причина использовать useCallback: стабильные пропсы для React.memo

Если передать обычную инлайн-функцию в пропсы мемоизированного дочернего компонента, он всё равно будет ререндериться, потому что функция создаётся заново при каждом рендере. useCallback сохраняет ссылку стабильной, и тогда React.memo может пропустить ререндер.

Пример

const Child = React.memo(({ onClick }) => );

function Parent() {
  const handleClick = useCallback(() => console.log('click'), []);
  return ;
}

Без useCallback Child будет ререндериться каждый раз, так как ссылка на функцию меняется.

4. Массив зависимостей так же легко обманывает, как и в useEffect

Здесь та же ловушка с устаревшими замыканиями. Если закэшировать функцию с useCallback(fn, []), а fn читает пропс или состояние извне, вы получите функцию, замороженную со значением на момент первого рендера. Решение — включить эту зависимость в массив, а не подавлять линтер.

Пример

function Component({ userId }) {
  const fetchData = useCallback(() => {
    fetch(`/api/user/${userId}`); // userId берётся из замыкания
  }, []); // userId не указан — будет использовано первое значение
  // Правильно: [userId]
}

5. Литералы объектов и массивов в зависимостях ломают мемоизацию

Выражение useMemo(() => doSomething(config), [config]) выглядит безопасным, но если config — это { foo: bar }, созданный инлайн на каждом рендере, зависимость меняется каждый раз, и мемоизация не срабатывает. Нужно вынести объект за пределы рендера или мемоизировать его отдельно.

Пример

const config = { foo: bar }; // создаётся каждый рендер
const result = useMemo(() => doSomething(config), [config]); // не работает

// Решение:
const config = useMemo(() => ({ foo: bar }), []);
const result = useMemo(() => doSomething(config), [config]);

Практический вывод

Теперь вы знаете, что useMemo и useCallback — не панацея. Прежде чем использовать их, спросите себя: «Действительно ли вычисление дорогое? Нужна ли стабильная ссылка?» Если нет — не используйте. Если да — не забывайте про зависимости. Попробуйте применить эти знания в своём проекте: найдите место, где useMemo или useCallback используются без необходимости, и удалите их. Замерьте производительность до и после. Увидите разницу — значит, было не зря.

#React#useMemo#useCallback#мемоизация
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →