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

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

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

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Как работает React.memo

React.memo — это HOC (Higher Order Component), который оптимизирует производительность компонента путём мемоизации. Компонент перерендеривается только если его props изменились.

Базовое использование

const MyComponent = ({ name, age }: Props) => {
  console.log("Компонент отрендерился");
  return <div>{name}, {age}</div>;
};

export default React.memo(MyComponent);

При перерендере родителя, если props не изменились, React пропустит перерендер дочернего компонента.

Как работает сравнение props

По умолчанию React.memo использует поверхностное сравнение (shallow comparison):

const obj1 = { value: 42 };
const obj2 = { value: 42 };

console.log(obj1 === obj2);  // false — разные ссылки

Это проблема для объектов и функций, потому что новый объект создаётся на каждом рендере:

const Parent = () => {
  const user = { name: "Alice" };  // новый объект каждый раз!
  
  return <Child user={user} />;    // memo видит новый props
};

const Child = React.memo(({ user }: Props) => {
  console.log("Child отрендерился");  // выполнится каждый раз!
  return <div>{user.name}</div>;
});

Решение 1: useMemo для объектов

const Parent = () => {
  const user = useMemo(() => ({ name: "Alice" }), []);
  
  return <Child user={user} />;
};

Решение 2: useCallback для функций

const Parent = () => {
  const handleClick = useCallback(() => {
    console.log("Clicked");
  }, []);  // зависимости
  
  return <Child onClick={handleClick} />;
};

Решение 3: Кастомная функция сравнения

Второй параметр memo — функция сравнения. Верни true если props «равны»:

const MyComponent = ({ user, settings }: Props) => {
  return <div>{user.name}</div>;
};

const arePropsEqual = (prevProps, nextProps) => {
  // Вернуть true = пропустить перерендер
  // Вернуть false = выполнить перерендер
  return prevProps.user.id === nextProps.user.id;
};

export default React.memo(MyComponent, arePropsEqual);

Практический пример: List с memo

interface ItemProps {
  id: number;
  name: string;
  onDelete: (id: number) => void;
}

const ListItem = React.memo(({ id, name, onDelete }: ItemProps) => {
  console.log(`Item ${id} rendered`);
  return (
    <li>
      {name}
      <button onClick={() => onDelete(id)}>Удалить</button>
    </li>
  );
});

const List = ({ items }: { items: Item[] }) => {
  const handleDelete = useCallback((id: number) => {
    // удалить элемент
  }, []);
  
  return (
    <ul>
      {items.map(item => (
        <ListItem
          key={item.id}
          id={item.id}
          name={item.name}
          onDelete={handleDelete}  // useCallback! иначе новая функция каждый раз
        />
      ))}
    </ul>
  );
};

Когда memo помогает

  • Тяжёлые компоненты с дорогими вычислениями
  • Списки с сотнями элементов
  • Чистые компоненты (pure components), которые зависят только от props
  • Часто обновляемые родители (Input, Slider, Animation)

Когда memo не поможет

  • Если родитель обновляется часто и всегда передаёт новые props
  • Если забыл обернуть в useMemo/useCallback объекты и функции
  • Если компонент маленький (переделать не стоит)
  • Если используешь render props или children (всегда новые ссылки)

Профилирование перерендеров

const Child = React.memo(({ name }: Props) => {
  console.log("Child rendered", name);
  return <div>{name}</div>;
}, (prevProps, nextProps) => {
  const equal = prevProps.name === nextProps.name;
  console.log(`Props equal: ${equal}`);
  return equal;
});

Важные моменты

  • Не оверюзь memo — микрооптимизация может замедлить разработку
  • Используй React DevTools Profiler для анализа перерендеров
  • memo + useMemo + useCallback = комбо для максимальной оптимизации списков