Коли використовувати useCallback()?
Коли використовувати useCallback()
Хук useCallback() потрібен не для прискорення функції,
а для того, щоб зберігати одне й те саме посилання на функцію між рендерами.
Це важливо, коли:
- Функція передається в дочірній компонент, особливо якщо він обгорнутий у
React.memo. - Функція використовується в
useEffect/useMemoі повинна залишатися стабільною (щоб не викликати ефект заново). - Ти хочеш уникнути зайвого пересоздання функцій при кожному рендері (що призводить до непотрібних перемальовувань).
Приклад 1: передача функції в React.memo-компонент
javascript
const Button = React.memo(({ onClick }) => {
console.log("Ререндер кнопки");
return <button onClick={onClick}>+</button>;
});
function Counter() {
const [count, setCount] = useState(0);
// Без useCallback → при кожному рендері створюється нова функція
const increment = useCallback(() => setCount(c => c + 1), []);
return (
<div>
<p>{count}</p>
<Button onClick={increment} />
</div>
);
}Тут:
incrementстворюється один раз, оскільки залежності -[].- Кнопка не перерендерюється без причини.
Без
useCallbackButtonререндерилась би при кожній змініcount.
Приклад 2: стабільна залежність у useEffect
javascript
function FetchUser({ id }) {
const fetchUser = useCallback(() => {
return fetch(`/api/user/${id}`).then(res => res.json());
}, [id]);
useEffect(() => {
fetchUser();
}, [fetchUser]); // useEffect викличеться тільки при зміні id
}Без useCallback fetchUser пересоздавалась би кожен рендер,
і useEffect викликався б кожного разу - навіть якщо id не змінився.
Підсумок - коли реально варто використовувати
| Ситуація | Чи варто використовувати? | Чому |
|---|---|---|
Передаєш функцію в React.memo компонент | Так | Уникаєш зайвих ререндерів |
Використовуєш функцію в useEffect / useMemo | Так | Стабілізуєш залежність |
| Виклик функції прямо всередині JSX | Ні | Немає сенсу, вона не зберігається |
| Функція не залежить від пропсів чи стану | Можна з [] | Створиться тільки один раз |
| Легка функція, що не впливає на інших | Ні | Оптимізація не виправдана |
Що станеться, якщо не вказати залежності
javascript
const memoizedFn = useCallback(() => {
doSomething(a, b);
});Без масиву залежностей:
-
useCallbackбуде пересоздавати функцію на кожному рендері - тобто ніякої мемоізації не відбудеться. -
Це еквівалентно простому написанню:
javascriptconst memoizedFn = () => doSomething(a, b);
Щоб useCallback працював, потрібно передати залежності,
за якими React розумітиме, коли функція дійсно повинна оновитися.
Приклад із залежностями
javascript
const handleClick = useCallback(() => {
console.log(count);
}, [count]);- Функція пересоздається тільки якщо змінився
count. - Якби ти не вказав
[count], то всередині функції завжди був би "заморожений"countз першого рендера.
Важливо пам'ятати
| Правило | Пояснення |
|---|---|
useCallback(fn, deps) кешує посилання на функцію | Функція створюється заново тільки при зміні залежностей |
| Якщо пропустити залежності | Функція буде пересоздаватися при кожному рендері (мемоізація не працює) |
Якщо поставити [] | Функція створюється один раз при монтуванні і ніколи не оновлюється |
| Вказуй усі значення, що використовуються всередині | Інакше замикання міститиме застарілі дані |
Підсумок
| Питання | Відповідь |
|---|---|
Коли використовувати useCallback() | Коли потрібно, щоб функція зберігала посилання між рендерами (React.memo, useEffect, useMemo) |
| Що станеться без залежностей | Функція буде пересоздаватися кожен рендер - мемоізація не працює |
Що буде з [] | Функція створиться один раз і ніколи не оновиться |
| Що повертає | Ту саму функцію, але з мемоізованим посиланням |
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.