useCallback — кључни појмови, хук мемоизације функција у React-у

Аутор: IT Sectr Објављено: 2026-07-04 Време читања: 9 мин

useCallback — React хук који враћа мемоизовану верзију функције, која се не мења између рендера док се не промене њене зависности. За разлику од уобичајеног декларисања функције унутар компоненте (које ствара нову функцију при сваком рендеру), useCallback стабилизује референцу функције, што спречава непотребне ре-рендере наследних компоненти оптимизованих кроз React.memo. Према React Documentation (2025), useCallback је користан само у пару са React.memo или хуковима који зависе од стабилне референце.

Кључно

  • useCallback — хук за мемоизацију функције, који чува референцу између рендера.
  • React.memo — useCallback је ефикасан само у пару са React.memo за спречавање ре-рендера.
  • Зависности — функција се поново креира само при промени наведених вредности у низу.
  • Стабилна референца — useCallback гарантује да се референца функције неће променити без потребе.
  • Не злоупотребљавај — прекомерни useCallback без React.memo погоршава перформансе.

Шта је useCallback у React-у

useCallback — хук додат у React 16.8 који мемоизије функцију: враћа исту референцу док се зависности не промене. Без useCallback свако декларисање функције унутар компоненте ствара нови објекат функције при сваком рендеру. За примитиве је то неприметно, али при прослеђивању таквих callback-ова наследним компонентама оптимизованим кроз React.memo, свака нова референца изазива ре-рендер наследне компоненте.

Синтактички, useCallback је еквивалентан useMemo за функцију: useCallback(fn, deps) — скраћеница је за useMemo(() => fn, deps). React чува мемоизовану функцију у унутрашњој меморији fiber чвора и упоређује зависности при сваком рендеру. Ако се зависности нису промениле (Object.is за сваки елемент), враћа се претходна функција.

Према React Documentation — useCallback (2025), не треба умотавати сваку функцију у useCallback. Хук има своју цену: позив хука, поређење зависности и алокација меморије за низ зависности. Ако је компонента једноставна и нема дубока стабла са React.memo — useCallback ће само успорити апликацију. Оптимизација мора бити мерљива, а не интуитивна.

jsx
import { useCallback } from 'react';

function Parent() {
    const [count, setCount] = useState(0);

    // Стабилна референца — иста функција док се deps не промене
    const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

    return <Child onClick={handleClick} />;
}

Како ради мемоизација функција

Мемоизација у useCallback заснива се на кеширању резултата позива функције. React чува closure створен у тренутку првог рендера и враћа га при наредним рендерима док зависности остају непромењене. Унутар fiber чвора сваки позив useCallback ствара чвор у повезаној листи хукова, где се чувају претходне зависности и мемоизована вредност.

Процес поређења зависности одвија се строго кроз Object.is — то је површно поређење, без дубоког проверавања објеката или низова. Ако се у зависностима налази објекат или низ, нова референца при сваком рендеру биће сматрана променом. Зато у низ зависности треба прослеђивати примитивне вредности или стабилне референце (на пример из useRef или useMemo).

Према React Core Team — Optimization Guide (2024), цена мемоизације укључује три компоненте: алокацију низа зависности при сваком рендеру, пролазак и поређење елемената кроз Object.is и потенцијални overhead од garbage collection при поновном креирању. За компоненту са стотинама useCallback омотача ово може постати приметно — зато је селективност у коришћењу хука критична.

СценариоБез useCallbackСа useCallback
Креирање функцијеНова при сваком рендеруИста при стабилним deps
Прослеђивање у React.memoДете се ре-рендеришеДете се не ре-рендерише
У низу useEffectЕфекат се поново покрећеЕфекат је стабилан
OverheadМинималанПоређење зависности + меморија

useCallback и перформансе

Распрострањен је мит да useCallback аутоматски побољшава перформансе. У ствари, у изолацији (без React.memo) useCallback чак и мало успорава апликацију због цене поређења зависности. Хук доноси стварну корист само у три сценарија: спречавање ре-рендера React.memo компоненти, стабилност callback-ова у useEffect и прослеђивање кастомним хуковима који зависе од reference equality.

Правило је једноставно: док не пронађеш проблем са перформансама кроз React DevTools Profiler — не користи useCallback. React тим је више пута истицао да је превремена оптимизација корен зла. Прво напиши чист код без мемоизације, измери, пронађи уско грло у профилеру и тек онда додај useCallback тамо где је стварно потребан.

jsx
// Мерљива оптимизација: Child је умотан у React.memo
const Child = React.memo(({ onClick }) => {
    console.log('Child је ре-рендерисан');
    return <button onClick={onClick}>Click</button>;
});

function Parent() {
    const handleClick = useCallback(() => {
        console.log('кликнуто');
    }, []);
    return <Child onClick={handleClick} />;
}

Према Dan Abramov — Before You memo() (2024), више од 90% случајева коришћења useCallback у open-source пројектима је сувишно. Програмери умотавају сваку функцију „за сваки случај", не мерећи ефекат. Алтернатива: ако је наследна компонента тешка и њен ре-рендер је скуп — React.memo + useCallback су оправдани. Ако је наследна компонента лагана — ре-рендер је јефтинији од поређења зависности.

Када користити useCallback

Први сценарио — React.memo. Ако је наследна компонента умотана у React.memo и прима callback функцију као prop, без useCallback наследна компонента ће се прецртавати при сваком рендеру родитеља, чак и ако се њени сопствени подаци нису променили. useCallback стабилизује референцу, па React.memo може исправно да прескочи ре-рендер.

Други сценарио — useEffect са callback-ом у зависностима. Ако се функција прослеђује у низ зависности useEffect, свака нова референца ће поново покренути ефекат. useCallback гарантује да је референца стабилна, па се ефекат извршава само при промени стварних података, а не при сваком рендеру. Ово је посебно важно за претплате и захтеве.

  • React.memo children — спречава ре-рендер мемоизованих наследних компоненти при прослеђивању callback-ова.
  • useEffect dependencies — стабилизује функцију у низу зависности ефекта, спречавајући непотребна поновна покретања.
  • Кастомни хукови — ако хук прима callback и зависи од његове reference equality, useCallback је обавезан.
  • Context value — ако се у value контекста прослеђује функција, useMemo са useCallback стабилизује референцу.
jsx
// useCallback за стабилну зависност useEffect
const fetchData = useCallback(async (id) => {
    const res = await fetch(`/api/${id}`);
    setData(res.data);
}, []); // стабилна референца, никад се не рекреира

useEffect(() => {
    fetchData(props.id);
}, [props.id, fetchData]); // ефекат се покреће само при промени props.id

useCallback vs useMemo

Главна разлика између useCallback и useMemo је у томе шта сваки мемоизије. useCallback мемоизије функцију: useCallback(fn, deps) враћа fn (исту или претходну верзију). useMemo мемоизије резултат позива функције: useMemo(() => computeExpensive(a, b), [a, b]) враћа израчунату вредност, а не функцију.

Технички, useCallback је синтактички шећер над useMemo: useCallback(fn, deps) је еквивалентан useMemo(() => fn, deps). Ова синтакса постоји само ради читљивости — да програмер јасно види да се мемоизије управо функција, а не вредност. Разлике у перформансама између useCallback и useMemo са функцијом нема — генеришу исти код.

ХукМемоизијеСинтаксаУпотреба
useCallbackФункцију (референцу)useCallback(fn, deps)Callback-ови за наследне компоненте
useMemoРезултат израчунавањаuseMemo(() => value, deps)Скупа израчунавања, мемоизација објеката
jsx
// Ово је еквивалентно:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);

Типичне грешке са useCallback

Најчешћа грешка — бесмислено умотавање свих функција у useCallback без React.memo на наследним компонентама. Ако наследна компонента није умотана у React.memo, она ће се ипак ре-рендерисати при сваком рендеру родитеља, без обзира на то да ли се референца callback-а мења или не. useCallback без React.memo — трошак без користи.

  • useCallback без React.memo — наследна компонента се ипак ре-рендерише; оптимизација је бесмислена.
  • Заборављене зависности — ако се унутар callback-а користи променљива ненаведена у deps, callback садржи stale closure.
  • Прекомерна мемоизација — умотавање сваке функције, укључујући тривијалне onClick са console.log.
  • Објекти и низови у зависностима — нова референца при сваком рендеру сматра се променом, мемоизација је бескорисна.
jsx
// ❌ Бескорисно: нема React.memo на child
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child се ипак ре-рендерише без React.memo

// ❌ Stale closure: недостаје зависност
const handle = useCallback(() => {
    console.log(count); // count је увек 0 — stale closure!
}, []);

// ✅ Исправно: укључи зависности
const handle = useCallback(() => {
    console.log(count);
}, [count]);

Проблем stale closure у useCallback решава се навођењем свих коришћених променљивих у низу зависности. eslint-plugin-react-hooks са exhaustive-deps аутоматски проверава да су све променљиве из тела callback-а присутне у низу. Ако callback користи setState, који се не мења између рендера, може се безбедно навести у deps — React гарантује стабилност setState.

Често постављана питања

Да ли треба умотавати сваку функцију у useCallback?

Не. useCallback има смисла само у три случаја: наследна компонента је умотана у React.memo, функција се користи у низу зависности useEffect или се функција прослеђује кастомном хуку који зависи од reference equality. У осталим случајевима useCallback додаје overhead без користи. React тим препоручује да прво пишете без оптимизација и да их додајете на основу резултата профилисања.

Шта је брже — useCallback или нова функција при сваком рендеру?

За једноставне компоненте — нова функција при сваком рендеру је мало бржа, јер useCallback троши ресурсе на поређење зависности и алокацију низа. За компоненте са дубоким стаблима React.memo — useCallback побеђује, спречавајући ре-рендер хиљада наследних елемената. Мери и упоређуј, а не нагађај — користи React DevTools Profiler за објективну процену.

Може ли се useCallback користити са async функцијама?

Да, useCallback ради са async функцијама потпуно исто као и са синхроним. Хук мемоизије саму функцију, а резултат (Promise) враћа се сваки пут при позиву. Асинхрона функција унутар useCallback је уобичајен образац за стабилне callback-ове учитавања података који се користе у useEffect: const fetchData = useCallback(async (id) => {...}, []).

Како отклонити проблем са useCallback и React.memo?

Користи React DevTools Profiler — показаће које компоненте се ре-рендеришу и зашто. За програмску проверу додај console.log или useWhyDidYouUpdate — библиотеку која бележи разлог ре-рендера. Главни разлози: променио се prop (укључујући референцу callback-а), променио се state или контекст. Ако useCallback не помаже — провери да ли су све зависности исправно наведене.

Како проследити useCallback наследној компоненти без React.memo?

Чак и без React.memo, useCallback може бити користан у комбинацији са useMemo за value контекста. Ако прослеђујеш објекат са функцијама у Context.Provider, умотај креирање објекта у useMemo, а сваку функцију у useCallback. Ово ће спречити ре-рендер свих потрошача контекста при промени једне од функција. Али за директно прослеђивање callback-ова у props без React.memo, useCallback нема користи.

Закључак

  • useCallback — хук за мемоизацију функције, који враћа стабилну референцу до промене зависности.
  • React.memo synergy — useCallback је ефикасан само у пару са React.memo на наследним компонентама.
  • Поређење зависности — кроз Object.is; објекти/низови у deps кваре мемоизацију.
  • Мери, не нагађај — додај useCallback само након проналажења уског грла кроз профилер.
  • Stable closure — укључи све коришћене променљиве у низ зависности, иначе — stale closure.
  • useCallback vs useMemo — useCallback мемоизије функцију, useMemo — резултат израчунавања.
  • Сувишност — више од 90% случајева коришћења useCallback у стварним пројектима је превремена оптимизација.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође