> Будет ли работать React.memo если пропсы передаются в виде объекта, который меняется по ссылке (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Иннотех

Стек: React

> Пример ответа

Короткий ответ

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

Подробное объяснение

React.memo - это HOC, который мемоизирует компонент и предотвращает его повторный рендер, если пропсы не изменились. По умолчанию он использует функцию сравнения, аналогичную Object.is, которая сравнивает пропсы по ссылке. Для примитивов (строки, числа) это работает корректно, так как одинаковые значения дают одинаковые ссылки. Но для объектов, массивов и функций каждый новый рендер родителя создаёт новый экземпляр с новой ссылкой, даже если содержимое не изменилось.

Это фундаментальное ограничение поверхностного сравнения в JavaScript. React не выполняет глубокое сравнение объектов по умолчанию, так как это было бы дорогостоящей операцией, особенно для глубоко вложенных структур. Поэтому React.memo видит, что ссылка изменилась, и считает пропсы "новыми", вызывая ререндер.

Решения:

  • Использовать useMemo для стабильной ссылки на объект
  • Передавать примитивные значения вместо объекта
  • Использовать кастомную функцию сравнения вторым аргументом React.memo

На практике

В реальных проектах эта проблема возникает часто, особенно при работе с конфигами, стилями или данными из API. Разработчики могут ожидать, что React.memo решит все проблемы с производительностью, но без стабилизации ссылок эффект будет нулевым.

Правильный подход - комбинировать React.memo с useMemo и useCallback для объектов и функций. Если объект создаётся внутри компонента, оберните его в useMemo с правильными зависимостями. Если объект приходит из внешнего источника (например, Redux), используйте селекторы, которые возвращают стабильные ссылки.

Кастомная функция сравнения - крайняя мера, так как она может привести к багам, если не учесть все поля. Лучше обеспечить стабильность ссылок на уровне родителя.

Пример кода

JSX
// Проблема: объект создаётся заново при каждом рендере
function Parent() {
const config = { theme: 'dark', size: 'large' };
return <Child config={config} />;
}
const Child = React.memo(({ config }) => {
console.log('Child rendered');
return <div>{config.theme}</div>;
});
// Child будет ререндериться каждый раз, несмотря на React.memo
// Решение 1: useMemo
function Parent() {
const config = useMemo(() => ({ theme: 'dark', size: 'large' }), []);
return <Child config={config} />;
}
// Решение 2: передача примитивов
function Parent() {
return <Child theme="dark" size="large" />;
}
const Child = React.memo(({ theme, size }) => {
console.log('Child rendered');
return <div>{theme}</div>;
});
// Решение 3: кастомное сравнение (не рекомендуется без необходимости)
const Child = React.memo(
({ config }) => <div>{config.theme}</div>,
(prevProps, nextProps) => prevProps.config.theme === nextProps.config.theme
);

Как отвечать на собеседовании

Начни с прямого ответа: "Нет, не будет работать, если объект создаётся заново". Объясни механизм поверхностного сравнения и почему ссылки важны. Приведи пример из практики, когда это приводит к неожиданным ререндерам. Затем предложи решения: useMemo, передача примитивов, кастомное сравнение. Упомяни trade-off: глубокое сравнение дорогое, поэтому React выбрал поверхностное. Если интервьюер спросит про производительность, добавь, что в большинстве случаев стабилизация ссылок через useMemo дешевле, чем глубокое сравнение в кастомной функции.

Что проверяет интервьюер

Интервьюер проверяет понимание механизма работы React.memo и поверхностного сравнения в JavaScript. Он хочет увидеть, что кандидат знает не только API, но и подводные камни. Также проверяется способность предлагать практические решения и понимание trade-off между производительностью и сложностью кода. Это вопрос senior-уровня, так как требует понимания внутреннего устройства React и оптимизации рендера.

Типичные ошибки

  • Утверждение, что React.memo делает глубокое сравнение объектов по умолчанию
  • Предложение использовать JSON.stringify в кастомной функции сравнения - это дорого и может привести к багам с циклическими ссылками
  • Игнорирование необходимости стабилизации функций через useCallback (аналогичная проблема)
  • Уверенность, что React.memo решит все проблемы производительности без анализа причин ререндеров
  • Использование кастомной функции сравнения без понимания, что она должна быть чистой и быстрой

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью