Проверяет понимание мемоизации функций в React и причин, по которым необёрнутая в useCallback функция вызывает лишние ререндеры дочерних компонентов.
В JavaScript функции — это объекты, и каждая новая функция, объявленная внутри компонента, создаётся заново при каждом рендере. Это значит, что ссылка на неё меняется, даже если тело функции идентично. React сравнивает пропсы поверхностно (shallow compare), поэтому новая ссылка воспринимается как изменение пропса.
Если дочерний компонент обёрнут в React.memo, он перерендерится только при изменении пропсов. Но новая функция в пропсе ломает эту оптимизацию: memo видит новую ссылку и запускает ререндер, хотя логика не поменялась.
function Parent() {
const [count, setCount] = useState(0);
// новая ссылка на каждом рендере
const handleClick = () => console.log('click');
return (
<>
<button onClick={() => setCount(count + 1)}>{count}</button>
<Child onClick={handleClick} />
</>
);
}
const Child = React.memo(({ onClick }) => {
console.log('Child render');
return <button onClick={onClick}>Child</button>;
});При каждом клике на родительскую кнопку Child будет перерендериваться, потому что handleClick — новая функция.
useCallback с корректным списком зависимостей.React.memo.const handleClick = useCallback(() => {
console.log('click');
}, []);Теперь ссылка стабильна, и Child не будет перерендериваться без необходимости.
Итог: useCallback стоит применять, когда функция передаётся в мемоизированный дочерний компонент или используется как зависимость в других хуках, иначе выгода от мемоизации теряется.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию