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

Что делает Memo?

2.0 Middle🔥 192 комментариев
#HTML и CSS

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

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

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

Что делает memo в React и зачем он нужен?

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

Как работает memo?

memo — это функция высшего порядка (HOC), которая принимает компонент и возвращает его мемоизированную версию. Мемоизированный компонент будет ререндерить только при изменении его пропсов. React сравнивает текущие пропсы с предыдущими, и если они одинаковы, использует сохраненный (запомненный) результат рендера.

Пример использования:

import React, { memo } from 'react';

const UserProfile = ({ name, age }) => {
  console.log('Рендер UserProfile');
  return (
    <div>
      <h2>{name}</h2>
      <p>Возраст: {age}</p>
    </div>
  );
};

// Мемоизируем компонент
const MemoizedUserProfile = memo(UserProfile);

// В родительском компоненте
const App = () => {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Клик: {count}</button>
      {/* Этот компонент не будет ререндериться при клике, так как его пропсы не меняются */}
      <MemoizedUserProfile name="Иван" age={30} />
    </div>
  );
};

В этом примере при каждом клике на кнопку состояние count в App изменяется, вызывая ререндер App. Однако MemoizedUserProfile получает неизменные пропсы (name и age), поэтому React пропускает его ререндер, и в консоли не появляется новый лог "Рендер UserProfile".

Глубокое сравнение пропсов и кастомная функция сравнения

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

Пример проблемы:

const Parent = () => {
  const user = { name: 'Иван', age: 30 }; // Новый объект при каждом рендере Parent
  
  return <MemoizedUserProfile user={user} />;
};

Здесь даже если user имеет одинаковые поля, каждый рендер Parent создает новый объект, поэтому memo увидит изменение пропсов и выполнит ререндер.

Для решения этой проблемы memo принимает второй аргумент — функцию сравнения пропсов.

const arePropsEqual = (prevProps, nextProps) => {
  // Сравниваем глубоко, только если поля name и age одинаковы
  return prevProps.user.name === nextProps.user.name 
    && prevProps.user.age === nextProps.user.age;
};

const MemoizedUserProfile = memo(UserProfile, arePropsEqual);

Когда использовать memo?

Оптимальные случаи для применения memo:

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

Когда memo не нужен или даже вреден:

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

memo и другие оптимизации React

memo часто используется вместе с:

  • useMemo — для мемоизации вычислений внутри компонента.
  • useCallback — для мемоизации функций, передаваемых как пропсы, чтобы memo мог корректно сравнивать их.
const Parent = () => {
  const [count, setCount] = useState(0);
  const onUpdate = useCallback(() => {
    // Логика
  }, []); // Функция не меняется между рендерами
  
  return <MemoizedChild onUpdate={onUpdate} />;
};

Выводы

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