Skip to main content

Що робить useCallback()?

Що робить useCallback()

useCallback() - це хук мемоізації функцій. Він повертає ту саму функцію (за посиланням) між рендерами, якщо залежності не змінилися.


Синтаксис:

javascript
const memoizedCallback = useCallback(callback, [deps]);
  • callback - сама функція, яку ти хочеш "запам'ятати".
  • [deps] - масив залежностей, від яких залежить ця функція.

Приклад без useCallback

javascript
function App() { const handleClick = () => console.log('click'); return <Button onClick={handleClick} />; }

Щоразу, коли компонент App ререндериться, React створює нову функцію handleClick. Навіть якщо логіка всередині не змінилася - посилання інше.

Якщо Button мемоізований (React.memo), React подумає:

«Проп onClick змінився (нове посилання) - потрібно ререндерити дитину.»

Підсумок: Button зайвий ререндер.


З useCallback

javascript
function App() { const handleClick = useCallback(() => console.log('click'), []); return <Button onClick={handleClick} />; }

Тепер:

  • handleClick створюється один раз;
  • При наступному рендері React поверне те саме посилання (якщо залежності не змінилися);
  • Для дочірнього React.memo-компонента проп onClick не змінився;
  • -> дочірній компонент не ререндериться.

Як це працює "під капотом"

React зберігає "стару" версію функції в пам'яті. При наступному рендері:

  • Порівнює залежності [deps];
  • Якщо нічого не змінилося, повертає старе посилання на функцію з пам'яті;
  • Якщо хоча б одна залежність змінилася - створює нову функцію і запам'ятовує її.

Приклад наочно

javascript
function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { console.log('clicked'); }, []); // залежності порожні -> посилання стабільне console.log('Parent render'); return ( <> <Child onClick={handleClick} /> <button onClick={() => setCount(c => c + 1)}>+</button> </> ); } const Child = React.memo(({ onClick }) => { console.log('Child render'); return <button onClick={onClick}>Child</button>; });

Без useCallback:

javascript
Parent render Child render Parent render Child render (зайвий)

З useCallback:

javascript
Parent render Child render Parent render (Child не ререндериться)

Коли useCallback реально допомагає

Використовуй, якщо:

  1. Колбек передається в мемоізований дочірній компонент (React.memo, useMemo тощо);
  2. Колбек бере участь у залежностях іншого useEffect / useMemo, і ти хочеш уникнути хибних перезапусків.

Коли useCallback не потрібен

  • Якщо функція використовується тільки всередині компонента (у JSX не передається в дочірні).
  • Якщо дитина не мемоізована (React.memo немає).
  • Якщо компонент і так ререндериться завжди (наприклад, у батька немає оптимізації).

useCallback не пришвидшує виконання функції. Він лише зберігає посилання, щоб React не думав, що вона "нова".


Паралель з useMemo

ХукЩо кешуєПовертає
useMemo(fn, deps)результат обчисленнязначення
useCallback(fn, deps)саму функціюфункцію

Приклад еквівалентності:

javascript
useCallback(fn, deps)useMemo(() => fn, deps);

Часті неточності у використанні

Невірні залежності: Якщо ти не додаси залежності, React буде використовувати застарілі дані із замикання.

javascript
// залежність count не вказана -> замикання const onClick = useCallback(() => console.log(count), []);

Правильно:

javascript
const onClick = useCallback(() => console.log(count), [count]);

Підсумок

Що робить useCallbackЯк допомагає
Кешує функцію між рендерамиУникає зайвого створення функцій
Повертає те саме посилання, якщо залежності не змінилисяПропси у дочірніх компонентів не "змінюються"
Працює в парі з React.memoДозволяє реально уникнути ререндеру дитини
Не пришвидшує код, не зменшує навантаження на CPUТільки стабілізує посилання

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.