Замыкания — пожалуй, одна из самых пугающих концепций JavaScript. Даже всезнающий ChatGPT скажет вам это. Во всяком случае, это одна из самых скрытых особенностей языка. Вы используете замыкания, когда пишите какой-либо React-код, чаще всего даже не осознавая этого. Но в конечном итоге от этой фичи никуда не деться: чтобы разрабатывать сложные и производительные React-приложения, придется овладеть ею.
Попробуем проникнуть в очередную тайну JavaScript-кода, чтобы выяснить:
Предупреждение: если вы никогда не сталкивались с замыканиями в React, эта статья может взорвать ваш мозг. Рекомендую запастись достаточным количеством шоколада, чтобы стимулировать клетки мозга во время чтения.
Представьте, что вы реализуете форму с несколькими полями ввода. Одно из полей представляет собой очень тяжелый компонент из какой-то внешней библиотеки. У вас нет доступа к его внутренним элементам, поэтому вы не можете устранить проблемы с его производительностью. Но этот компонент очень нужен в форме, поэтому вы решили обернуть его в React.memo, чтобы минимизировать повторные рендеринги при изменении состояния формы. Как-то так:
const HeavyComponentMemo = React.memo(HeavyComponent);
const Form = () => {
const [value, setValue] = useState();
return (
<>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<HeavyComponentMemo />
</>
);
};
Пока все хорошо. Тяжелый компонент принимает только одно строковое свойство, например title, и коллбэк onClick. Это происходит при нажатии кнопки “done” (“готово”) внутри компонента. Отправить данные формы также довольно просто: достаточно передать title и onClick.
const HeavyComponentMemo = React.memo(HeavyComponent);
const Form = () => {
const [value, setValue] = useState();
const onClick = () => {
// сюда передаем данные формы
console.log(value);
};
return (
<>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<HeavyComponentMemo
title="Welcome to the form"
onClick={onClick}
/>
</>
);
};
А вот теперь перед вами встает дилемма. Как известно, каждое свойство компонента, обернутое в React.memo, должно быть либо примитивным значением, либо постоянным между повторными рендерами. В противном случае мемоизация не сработает. Поэтому технически нужно обернуть onClick в useCallback:
const onClick = useCallback(() => {
// здесь передаем данные
}, []);
Но, как известно, хук useCallback должен иметь все зависимости, объявленные в его массиве зависимостей. Поэтому, чтобы отправить данные формы в компонент, нужно объявить эти данные как зависимость:
🚀Смотреть
@react_tg