useCallback — klíčové pojmy, hook pro memoizaci funkcí v Reactu

Autor: IT Sectr Publikováno: 2026-07-04 Doba čtení: 9 min

useCallback — je React hook, který vrací memoizovanou verzi funkce, která se nemění mezi rendery, dokud se nezmění její závislosti. Na rozdíl od běžného deklarování funkce uvnitř komponenty (které při každém renderu vytváří novou funkci) useCallback stabilizuje referenci na funkci, čímž zabraňuje zbytečným re-renderům dětských komponent optimalizovaných přes React.memo. Podle React Documentation (2025) je useCallback užitečný pouze ve spojení s React.memo nebo hooky, které závisí na stabilní referenci.

Hlavní body

  • useCallback — hook pro memoizaci funkce, který zachovává referenci mezi rendery.
  • React.memo — useCallback je účinný pouze ve spojení s React.memo pro zabránění re-renderům.
  • Závislosti — funkce se znovu vytváří pouze při změně uvedených hodnot v poli.
  • Stabilní reference — useCallback zaručuje, že se reference na funkci zbytečně nezmění.
  • Nepřeháněj — nadměrný useCallback bez React.memo zhoršuje výkon.

Co je useCallback v Reactu

useCallback — je hook přidaný v Reactu 16.8, který memoizuje funkci: vrací stejnou referenci, dokud se závislosti nezmění. Bez useCallback každé deklarování funkce uvnitř komponenty vytváří při každém renderu nový objekt funkce. U primitiv je to nepostřehnutelné, ale při předávání takových callbacků dětským komponentám optimalizovaným přes React.memo každá nová reference způsobuje re-render dětské komponenty.

Syntakticky je useCallback ekvivalentní useMemo pro funkci: useCallback(fn, deps) — je zkratka pro useMemo(() => fn, deps). React ukládá memoizovanou funkci do vnitřního úložiště uzlu fiber a při každém renderu porovnává závislosti. Pokud se závislosti nezměnily (Object.is pro každý prvek), vrací se předchozí funkce.

Podle React Documentation — useCallback (2025) není třeba obalovat každou funkci do useCallback. Hook má svou cenu: volání hooku, porovnávání závislostí a alokace paměti pro pole závislostí. Pokud je komponenta jednoduchá a nemá hluboké stromy s React.memo — useCallback bude aplikaci jen zpomalovat. Optimalizace musí být měřitelná, ne intuitivní.

jsx
import { useCallback } from 'react';

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

    // Stabilní reference — stejná funkce, dokud se deps nezmění
    const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

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

Jak funguje memoizace funkcí

Memoizace v useCallback je založena na ukládání výsledku volání funkce do mezipaměti. React uchovává closure vytvořené v okamžiku prvního renderu a vrací je při dalších renderech, dokud závislosti zůstávají nezměněné. Uvnitř uzlu fiber každé volání useCallback vytváří uzel v propojeném seznamu hooků, kde se ukládají předchozí závislosti a memoizovaná hodnota.

Proces porovnávání závislostí probíhá přísně přes Object.is — jde o povrchní porovnání bez hluboké kontroly objektů nebo polí. Pokud je v závislostech objekt nebo pole, nová reference při každém renderu bude považována za změnu. Proto je třeba do pole závislostí předávat primitivní hodnoty nebo stabilní reference (například z useRef nebo useMemo).

Podle React Core Team — Optimization Guide (2024) zahrnuje náklad memoizace tři složky: alokaci pole závislostí při každém renderu, procházení a porovnávání prvků přes Object.is a potenciální overhead z garbage collection při znovuvytváření. U komponenty se stovkami useCallback obalů se to může stát znatelným — proto je selektivita v používání hooku kritická.

ScénářBez useCallbackS useCallback
Vytvoření funkceNová při každém renderuStejná při stabilních deps
Předání do React.memoDítě se re-renderujeDítě se nere-renderuje
V poli useEffectEfekt se restartujeEfekt je stabilní
OverheadMinimálníPorovnání závislostí + paměť

useCallback a výkon

Je rozšířený mýtus, že useCallback automaticky zlepšuje výkon. Ve skutečnosti v izolaci (bez React.memo) useCallback aplikaci dokonce mírně zpomaluje kvůli nákladům na porovnávání závislostí. Hook přináší skutečný užitek pouze ve třech scénářích: zabránění re-renderům React.memo komponent, stabilita callbacků v useEffect a předání custom hookům, které závisí na reference equality.

Pravidlo je jednoduché: dokud nenajdeš problém s výkonem přes React DevTools Profiler — useCallback nepoužívej. React tým opakovaně zdůrazňoval, že předčasná optimalizace je kořenem zla. Nejprve napiš čistý kód bez memoizace, změř, najdi úzké hrdlo v profileru a teprve poté přidej useCallback tam, kde je skutečně potřeba.

jsx
// Měřitelná optimalizace: Child je obalen v React.memo
const Child = React.memo(({ onClick }) => {
    console.log('Child se re-renderoval');
    return <button onClick={onClick}>Click</button>;
});

function Parent() {
    const handleClick = useCallback(() => {
        console.log('kliknuto');
    }, []);
    return <Child onClick={handleClick} />;
}

Podle Dan Abramov — Before You memo() (2024) je více než 90 % případů použití useCallback v open-source projektech nadbytečných. Vývojáři obalují každou funkci „pro jistotu", aniž by měřili účinek. Alternativa: pokud je dětská komponenta těžká a její re-render je nákladný — React.memo + useCallback jsou opodstatněné. Pokud je dětská komponenta lehká — re-render je levnější než porovnávání závislostí.

Kdy použít useCallback

První scénář — React.memo. Pokud je dětská komponenta obalena v React.memo a přijímá callback funkci jako prop, bez useCallback se dětská komponenta bude překreslovat při každém renderu rodiče, i když se její vlastní data nezměnila. useCallback stabilizuje referenci a React.memo může správně přeskočit re-render.

Druhý scénář — useEffect s callbackem v závislostech. Pokud se funkce předává do pole závislostí useEffect, každá nová reference restartuje efekt. useCallback zaručuje, že reference je stabilní, a efekt se spouští pouze při změně skutečných dat, ne při každém renderu. To je důležité zejména pro odběry a požadavky.

  • React.memo children — zabraňuje re-renderům memoizovaných dětských komponent při předávání callbacků.
  • useEffect dependencies — stabilizuje funkci v poli závislostí efektu a zabraňuje zbytečným restartům.
  • Custom hooky — pokud hook přijímá callback a závisí na jeho reference equality, je useCallback povinný.
  • Context value — pokud se v value kontextu předává funkce, useMemo s useCallback stabilizuje referenci.
jsx
// useCallback pro stabilní závislost useEffect
const fetchData = useCallback(async (id) => {
    const res = await fetch(`/api/${id}`);
    setData(res.data);
}, []); // stabilní reference, nikdy se znovu nevytváří

useEffect(() => {
    fetchData(props.id);
}, [props.id, fetchData]); // efekt běží pouze při změně props.id

useCallback vs useMemo

Hlavní rozdíl mezi useCallback a useMemo je v tom, co každý z nich memoizuje. useCallback memoizuje funkci: useCallback(fn, deps) vrací fn (stejnou nebo předchozí verzi). useMemo memoizuje výsledek volání funkce: useMemo(() => computeExpensive(a, b), [a, b]) vrací vypočtenou hodnotu, nikoli funkci.

Technicky je useCallback syntaktický cukr nad useMemo: useCallback(fn, deps) je ekvivalentní useMemo(() => fn, deps). Tato syntaxe existuje pouze pro čitelnost — aby vývojář jasně viděl, že se memoizuje právě funkce, ne hodnota. Mezi useCallback a useMemo s funkcí není žádný výkonnostní rozdíl — generují stejný kód.

HookMemoizujeSyntaxePoužití
useCallbackFunkci (referenci)useCallback(fn, deps)Callbacky pro dětské komponenty
useMemoVýsledek výpočtuuseMemo(() => value, deps)Nákladné výpočty, memoizace objektů
jsx
// Tyto jsou ekvivalentní:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);

Typické chyby s useCallback

Nejčastější chybou je nesmyslné obalování všech funkcí do useCallback bez React.memo na dětských komponentách. Pokud dětská komponenta není obalena v React.memo, bude se re-renderovat při každém renderu rodiče bez ohledu na to, zda se reference callbacku mění či nikoli. useCallback bez React.memo — náklady bez přínosu.

  • useCallback bez React.memo — dětská komponenta se stejně re-renderuje; optimalizace je nesmyslná.
  • Zapomenuté závislosti — pokud se uvnitř callbacku používá proměnná neuvedená v deps, callback obsahuje stale closure.
  • Nadměrná memoizace — obalování každé funkce, včetně triviálních onClick s console.log.
  • Objekty a pole v závislostech — nová reference při každém renderu je považována za změnu, memoizace je k ničemu.
jsx
// ❌ K ničemu: bez React.memo na child
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child se bez React.memo stejně re-renderuje

// ❌ Stale closure: chybějící závislost
const handle = useCallback(() => {
    console.log(count); // count je vždy 0 — stale closure!
}, []);

// ✅ Správně: zahrň závislosti
const handle = useCallback(() => {
    console.log(count);
}, [count]);

Problém stale closure v useCallback se řeší uvedením všech použitých proměnných v poli závislostí. eslint-plugin-react-hooks s exhaustive-deps automaticky kontroluje, že všechny proměnné z těla callbacku jsou v poli přítomny. Pokud callback používá setState, který se mezi rendery nemění, lze jej bezpečně uvést v deps — React zaručuje stabilitu setState.

Často kladené dotazy

Musím obalit každou funkci do useCallback?

Ne. useCallback má smysl pouze ve třech případech: dětská komponenta je obalena v React.memo, funkce se používá v poli závislostí useEffect nebo se funkce předává custom hooku závislému na reference equality. V ostatních případech useCallback přidává overhead bez přínosu. React tým doporučuje nejprve psát bez optimalizací a přidávat je podle výsledků profilování.

Co je rychlejší — useCallback nebo nová funkce při každém renderu?

U jednoduchých komponent je nová funkce při každém renderu o něco rychlejší, protože useCallback vynakládá prostředky na porovnávání závislostí a alokaci pole. U komponent s hlubokými stromy React.memo useCallback vítězí, protože zabraňuje re-renderu tisíců dětských prvků. Měř a porovnávej, nehádej — pro objektivní posouzení použij React DevTools Profiler.

Lze použít useCallback s async funkcemi?

Ano, useCallback funguje s async funkcemi přesně stejně jako se synchronními. Hook memoizuje samotnou funkci a výsledek (Promise) se vrací při každém volání. Asynchronní funkce uvnitř useCallback je častý vzor pro stabilní callbacky načítání dat používané v useEffect: const fetchData = useCallback(async (id) => {...}, []).

Jak vyřešit problém s useCallback a React.memo?

Použij React DevTools Profiler — ukáže, které komponenty se re-renderují a proč. Pro programovou kontrolu přidej console.log nebo useWhyDidYouUpdate — knihovnu, která loguje příčinu re-renderu. Hlavní příčiny: změnil se prop (včetně reference callbacku), změnil se state nebo kontext. Pokud useCallback nepomáhá — zkontroluj, že jsou všechny závislosti správně uvedeny.

Jak předat useCallback dětské komponentě bez React.memo?

I bez React.memo může být useCallback užitečný v kombinaci s useMemo pro value kontextu. Pokud předáváš objekt s funkcemi do Context.Provider, obal vytvoření objektu do useMemo a každou funkci do useCallback. Zabrání to re-renderu všech spotřebitelů kontextu při změně jedné z funkcí. Ale při přímém předávání callbacků v props bez React.memo useCallback nepřináší užitek.

Závěr

  • useCallback — hook pro memoizaci funkce, který vrací stabilní referenci až do změny závislostí.
  • React.memo synergy — useCallback je účinný pouze ve spojení s React.memo na dětských komponentách.
  • Porovnání závislostí — přes Object.is; objekty/pole v deps kazí memoizaci.
  • Měř, nehádej — přidávej useCallback pouze po nalezení úzkého hrdla přes profiler.
  • Stable closure — zahrň všechny použité proměnné do pole závislostí, jinak — stale closure.
  • useCallback vs useMemo — useCallback memoizuje funkci, useMemo — výsledek výpočtu.
  • Nadbytečnost — více než 90 % případů použití useCallback v reálných projektech je předčasná optimalizace.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také