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

С каким хуком обычно используют Memo

2.0 Middle🔥 181 комментариев
#JavaScript Core#React

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

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

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

Какой хук обычно используют с memo?

Наиболее частый и естественный спутник React.memo — это хук useMemo. Эти две оптимизации работают в тандеме для предотвращения лишних ререндеров компонентов, но решают задачи на разных уровнях: memo оптимизирует перерисовку целого компонента, а useMemo — вычисление значений внутри него.

Однако связка с useCallback также крайне важна. Давайте разберем оба случая подробно.

1. useMemo — для мемоизации значений и сложных вычислений

React.memo сравнивает пропсы компонента поверхностно (shallow compare). Если в пропсах передаются вычисленные значения (массивы, объекты), создаваемые заново при каждом рендере родителя, memo не сработает — пропсы будут считаться разными. Здесь нужен useMemo.

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

const ExpensiveChildComponent = memo(({ items, filterValue }) => {
  // Допустим, фильтрация очень дорогая
  const filteredItems = useMemo(() => {
    console.log('Выполняется тяжелая фильтрация...');
    return items.filter(item => item.includes(filterValue));
  }, [items, filterValue]); // Пересчитываем только при изменении items или filterValue

  return (
    <ul>
      {filteredItems.map(item => <li key={item}>{item}</li>)}
    </ul>
  );
});

function ParentComponent() {
  const [items] = useState(['Apple', 'Banana', 'Cherry']);
  const [filter, setFilter] = useState('');

  // Без useMemo этот объект создавался бы заново каждый рендер, и memo не работал бы
  const config = useMemo(() => ({
    items,
    filterValue: filter,
    theme: 'dark'
  }), [items, filter]);

  return <ExpensiveChildComponent {...config} />;
}

Ключевой момент: useMemo внутри мемоизированного компонента (memo) защищает от лишних вычислений внутри компонента, а также помогает стабилизировать сложные пропсы, передаваемые вниз дочерним компонентам.

2. useCallback — для мемоизации функций

Это самая критичная связка. Чаще всего React.memo ломается из-за того, что в пропсах передаются колбэки, создаваемые заново при каждом рендере родителя.

import React, { useState, memo, useCallback } from 'react';

const Button = memo(({ onClick, label }) => {
  console.log(`Рендер кнопки: ${label}`);
  return <button onClick={onClick}>{label}</button>;
});

function ParentComponent() {
  const [count, setCount] = useState(0);

  // БЕЗ useCallback: при каждом рендере Parent создается новая функция
  // Button (обернутый в memo) будет перерисовываться каждый раз!
  // const handleIncrement = () => setCount(c => c + 1);

  // С useCallback: функция стабилизируется, memo может предотвратить ререндер
  const handleIncrement = useCallback(() => setCount(c => c + 1), []);

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={handleIncrement} label="Increment" />
    </div>
  );
}

Итог: Когда и что использовать

  • React.memo + useCallbackобязательная комбинация, когда вы передаете функции как пропсы в мемоизированный дочерний компонент. Без useCallback мемоизация компонента (memo) практически бесполезна.
  • React.memo + useMemo — используется в двух сценариях:
    1.  Когда внутри мемоизированного компонента есть **ресурсоемкие вычисления**, которые не должны повторяться при каждом ререндере (даже если компонент и перерисовывается).
    2.  Когда вы передаете в мемоизированный компонент **сложные объекты или массивы** в качестве пропсов. `useMemo` стабилизирует ссылку на этот объект.

Важное предупреждение

Не стоит оборачивать в memo и useMemo/useCallback все подряд. Оптимизация имеет свою стоимость (сравнение пропсов, выделение памяти). Используйте эти инструменты осознанно:

  • Когда компонент часто ререндерится с одними и теми же пропсами.
  • Когда рендер компонента действительно тяжелый (содержит много элементов, сложную логику).
  • Когда компонент является «бутылочным горлышком», определенным с помощью профилировщика React DevTools.

Правильный подход — сначала написать чистый код без оптимизаций, а затем, при необходимости, добавить memo и соответствующие хуки, основываясь на данных профилирования.