← Назад к вопросам

Какие знаешь особенности зависимостей useMemo?

2.0 Middle🔥 261 комментариев
#React#Оптимизация и производительность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Особенности useMemo в React

useMemo — это хук в React, предназначенный для мемоизации (кеширования) вычислений между рендерами. Его основная задача — оптимизировать производительность компонентов, предотвращая дорогостоящие пересчеты при каждом обновлении. Вот ключевые особенности и нюансы использования:

1. Предотвращение повторных вычислений

Основная цель useMemo — избегать выполнения ресурсоёмких операций при каждом рендере. Хук кеширует результат функции и возвращает его, пока зависимости не изменились.

const memoizedValue = useMemo(() => {
  // Дорогостоящее вычисление, например, сортировка большого массива
  return expensiveComputation(data);
}, [data]); // Вычисляется только при изменении `data`

2. Зависимости (dependency array)

Второй аргумент useMemo — массив зависимостей. Важно:

  • При пустом массиве [] значение вычисляется единожды при монтировании компонента.
  • Если зависимости не переданы, значение пересчитывается при каждом рендере (сводит пользу хука на нет).
  • React использует поверхностное сравнение (shallow comparison) для проверки изменений зависимостей. Изменение ссылки на объект или массив вызовет пересчёт, даже если их содержимое идентично.
// Проблема: объект создаётся заново при каждом рендере -> пересчёт
const obj = { id: 1 };
const value = useMemo(() => compute(obj), [obj]);

// Решение: мемоизировать или примитивизировать зависимость
const obj = useMemo(() => ({ id: 1 }), []);
const value = useMemo(() => compute(obj), [obj.id]); // Используем примитив

3. Оптимизация для дочерних компонентов

useMemo часто используют, чтобы предотвратить лишние рендеры дочерних компонентов, передавая им мемоизированные пропсы. Это особенно важно для компонентов, обёрнутых в React.memo.

const Child = React.memo(({ list }) => {
  // Рендерится только при изменении `list`
});

const Parent = () => {
  const memoizedList = useMemo(() => {
    return items.filter(item => item.active);
  }, [items]);

  return <Child list={memoizedList} />;
};

4. Не для побочных эффектов

Критически важно: useMemo предназначен только для вычислений и возврата значения. Не используйте его для:

  • Побочных эффектов (например, запросов к API, подписок) — для этого есть useEffect.
  • Создания обработчиков событий — обычно для этого используют useCallback.

5. Гарантии и семантика выполнения

  • React может отбрасывать мемоизированные значения для освобождения памяти или при перерисовке в режиме Concurrent React. Поэтому не стоит полагаться на useMemo для гарантированного сохранения значения.
  • Вычисления внутри useMemo выполняются во время рендеринга, поэтому они должны быть быстрыми или "тяжёлыми", но не блокирующими. Для длительных вычислений рассмотрите useDeferredValue или вынос в Web Worker.

6. Когда использовать (и когда не использовать)

Используйте useMemo, когда:

  • Вычисление объективно медленное (фильтрация, сортировка больших массивов, сложные математические операции).
  • Вы передаёте вычисленное значение в React.memo-компонент и хотите избежать лишних рендеров.
  • Значение используется в других хуках (например, в useEffect) и вы хотите стабилизировать зависимость.

Не используйте useMemo:

  • Для всех вычислений без разбора — накладные расходы на сравнение зависимостей и мемоизацию могут превысить выгоду.
  • Для простых операций (например, конкатенация строк, базовые арифметические действия).
  • Когда преждевременная оптимизация усложняет код без измеримой пользы для производительности.

7. Сравнение с useCallback

  • useMemo возвращает мемоизированное значение.
  • useCallback возвращает мемоизированную функцию.
// useMemo: мемоизация результата функции
const memoizedValue = useMemo(() => someFunction(), [deps]);

// useCallback: мемоизация самой функции (эквивалент useMemo для функций)
const memoizedFunction = useCallback(someFunction, [deps]);
// То же самое через useMemo:
const memoizedFunction = useMemo(() => someFunction, [deps]);

Вывод

useMemo — мощный инструмент оптимизации, но его следует применять обдуманно. Профилируйте приложение с помощью React DevTools (вкладка "Profiler"), чтобы находить реальные узкие места, а не оптимизировать наугад. Помните: чистота кода и читаемость часто важнее микро-оптимизаций, которые не дают заметного прироста производительности. Используйте useMemo там, где есть измеримая проблема с рендерингом или вычислениями, а не "на всякий случай".