Почему React.memo не всегда спасает от рендеринга?
В React паттерны вроде React.memo используются разработчиками для предотвращения ненужных повторных рендеров компонентов. Однако есть распространённая ошибка, которая сводит на нет всю оптимизацию.
Проблема inline-пропсов
Когда вы передаёте функции или объекты напрямую через пропсы (props), каждый раз создаётся новая ссылка на объект. Это приводит к тому, что даже если данные внутри объекта остаются неизменными, компонент всё равно будет повторно отображаться, так как React видит новую ссылку.
const MyComponent = () => {
const handleClick = () => console.log('clicked');
return <Child onClick={handleClick} />;
};
Здесь функция handleClick создаётся заново при каждом рендеринге родительского компонента, вызывая повторный рендеринг дочернего компонента Child, несмотря на использование React.memo.
Как решить проблему?
Есть несколько способов решения этой проблемы:
Использование useCallback
Функция useCallback позволяет сохранить ссылку на функцию между рендерами, предотвращая создание новой ссылки при каждом обновлении.
import { useCallback } from 'react';
const MyComponent = () => {
const handleClick = useCallback(() => console.log('clicked'), []);
return <Child onClick={handleClick} />;
};
Теперь функция handleClick будет создана только один раз, а её ссылка останется прежней до тех пор, пока массив зависимостей пуст.
Избегайте создания объектов в render-функции
Если вам нужно передать объект через пропс, убедитесь, что этот объект создан вне области рендера или используйте мемоизированные значения.
const myObject = { key: 'value' };
const MyComponent = () => (
<Child objectProp={myObject} />
);
Таким образом, объект будет создан единожды, и его ссылка останется постоянной.