Вопрос проверяет понимание механизмов мемоизации в React и их совместного использования для оптимизации производительности.
React.memo — это HOC (Higher-Order Component), который запоминает результат рендера компонента и перерисовывает его только при изменении пропсов. Он использует поверхностное сравнение (shallow comparison) предыдущих и новых пропсов. Если пропсы не изменились, React.memo возвращает закэшированный результат, избегая лишнего рендера.
useCallback — это хук, который возвращает мемоизированную версию функции. Он принимает функцию и массив зависимостей. Пока зависимости не меняются, useCallback возвращает ту же самую ссылку на функцию. Это критично, потому что в JavaScript каждая новая функция — это новый объект в памяти.
useMemo — хук для мемоизации результатов вычислений. Он принимает функцию-вычислитель и массив зависимостей. Результат вычисления кэшируется и пересчитывается только при изменении зависимостей.
Когда родительский компонент перерисовывается, все функции, объявленные внутри него, создаются заново. Если вы передаёте такую функцию как пропс в дочерний компонент, обёрнутый в React.memo, то при каждом рендере родителя дочерний компонент получает новую ссылку на функцию. React.memo при поверхностном сравнении видит, что пропс изменился (старая ссылка !== новая ссылка), и перерисовывает дочерний компонент, несмотря на то, что логика функции не изменилась.
Пример:
import React, { useState, useCallback } from 'react';
const Child = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const [count, setCount] = useState(0);
// Без useCallback: каждый рендер создаёт новую функцию
const handleClick = useCallback(() => {
console.log('Clicked');
}, []);
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<Child onClick={handleClick} />
</>
);
}В этом примере без useCallback каждый клик на Increment вызывал бы перерисовку Child, даже если onClick не меняется. С useCallback ссылка стабильна, и Child не перерисовывается лишний раз.
Используйте useCallback для функций, передаваемых в компоненты, обёрнутые в React.memo, чтобы сохранить преимущества мемоизации. Это особенно важно в больших списках, сложных формах или компонентах с тяжёлым рендером. Однако не стоит оборачивать каждую функцию — применяйте оптимизацию только там, где это действительно необходимо для производительности.
Уровень
Рейтинг:
4
Сложность:
6
Навыки
JavaScript
React
Ключевые слова
Подпишись на React Developer в телеграм
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию