useCallback — kulcsfogalmak, a függvények memoizációjának hook-ja a React-ben

Szerző: IT Sectr Megjelenés: 2026-07-04 Olvasási idő: 9 perc

useCallback — egy React hook, amely a függvény memoizált változatát adja vissza, ami nem változik a renderelések között, amíg a függőségei nem változnak. Ellentétben a függvény komponensen belüli szokásos deklarálásával (amely minden renderelésnél új függvényt hoz létre), a useCallback stabilizálja a függvényre mutató referenciát, ami megakadályozza a React.memo-val optimalizált gyermekkomponensek felesleges újrarenderelését. A React Documentation (2025) szerint a useCallback csak a React.memo-val párosítva vagy stabil referenciától függő hook-okkal együtt hasznos.

A lényeg

  • useCallback — a függvény memoizálására szolgáló hook, amely megtartja a referenciát a renderelések között.
  • React.memo — a useCallback csak a React.memo-val párosítva hatékony az újrarenderelések megelőzésére.
  • Függőségek — a függvény csak a tömbben megadott értékek változásakor jön létre újra.
  • Stabil referencia — a useCallback garantálja, hogy a függvényreferencia szükségtelenül ne változzon.
  • Ne használd túl — a React.memo nélküli túlzott useCallback rontja a teljesítményt.

Mi az a useCallback a React-ben

useCallback — a React 16.8-ban hozzáadott hook, amely memoizálja a függvényt: addig ugyanazt a referenciát adja vissza, amíg a függőségek nem változnak. useCallback nélkül a komponensen belüli függvény minden deklarálása minden renderelésnél új függvényobjektumot hoz létre. Primitíveknél ez észrevehetetlen, de az ilyen callback-ek React.memo-val optimalizált gyermekkomponenseknek való átadásakor minden új referencia a gyermekkomponens újrarenderelését okozza.

Szintaktikailag a useCallback egyenértékű a useMemo-val függvényeknél: a useCallback(fn, deps) — rövidítése a useMemo(() => fn, deps) kifejezésnek. A React a memoizált függvényt a fiber-csomópont belső tárhelyén tárolja, és minden renderelésnél összehasonlítja a függőségeket. Ha a függőségek nem változtak (Object.is minden elemre), az előző függvény kerül visszaadásra.

A React Documentation — useCallback (2025) szerint nem szabad minden függvényt useCallback-be csomagolni. A hook-nak saját ára van: a hook meghívása, a függőségek összehasonlítása és memóriaallokáció a függőségi tömbhöz. Ha a komponens egyszerű, és nincsenek mély fái React.memo-val — a useCallback csak lassítani fogja az alkalmazást. Az optimalizációnak mérhetőnek kell lennie, nem intuitívnak.

jsx
import { useCallback } from 'react';

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

    // Stabil referencia — ugyanaz a függvény, amíg a deps nem változik
    const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

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

Hogyan működik a függvénymemoizáció

A useCallback memoizációja a függvényhívás eredményének gyorsítótárazásán alapul. A React megtartja az első rendereléskor létrehozott closure-t, és a következő rendereléseknél visszaadja, amíg a függőségek változatlanok maradnak. A fiber-csomóponton belül minden useCallback-hívás csomópontot hoz létre a hook-ok láncolt listájában, ahol az előző függőségeket és a memoizált értéket tárolják.

A függőségek összehasonlításának folyamata szigorúan az Object.is segítségével történik — ez felszínes összehasonlítás, objektumok vagy tömbök mély vizsgálata nélkül. Ha a függőségekben objektum vagy tömb van, a minden renderelésnél keletkező új referencia változásként lesz értelmezve. Ezért a függőségi tömbben primitív értékeket vagy stabil referenciákat (például useRef-ből vagy useMemo-ból) kell átadni.

A React Core Team — Optimization Guide (2024) szerint a memoizáció költsége három összetevőből áll: a függőségi tömb allokációja minden renderelésnél, az elemek bejárása és összehasonlítása Object.is segítségével, valamint az újraalkotás során a szemétgyűjtés lehetséges többletterhelése. Egy több száz useCallback-csomagolást tartalmazó komponensnél ez észrevehetővé válhat — ezért a szelektivitás kritikus a hook használatában.

ForgatókönyvuseCallback nélküluseCallback-kel
Függvény létrehozásaÚj minden renderelésnélUgyanaz stabil deps esetén
Átadás React.memo-nakA gyermek újrarenderelődikA gyermek nem renderelődik újra
useEffect tömbbenAz effekt újraindulAz effekt stabil
TöbbletterhelésMinimálisFüggőségek összehasonlítása + memória

useCallback és a teljesítmény

Elterjedt mítosz, hogy a useCallback automatikusan javítja a teljesítményt. Valójában elszigetelten (React.memo nélkül) a useCallback kissé le is lassítja az alkalmazást a függőségek összehasonlításának költsége miatt. A hook csak három forgatókönyvben hoz valódi hasznot: a React.memo-komponensek újrarenderelésének megelőzése, a callback-ek stabilitása a useEffect-ben, és átadás a reference equality-től függő egyedi hook-oknak.

A szabály egyszerű: amíg nem találsz teljesítményproblémát a React DevTools Profiler segítségével — ne használj useCallback-et. A React csapata többször hangsúlyozta, hogy a korai optimalizálás a rossz gyökere. Először írj tiszta kódot memoizáció nélkül, mérj, találd meg a szűk keresztmetszetet a profilozóban, és csak utána add hozzá a useCallback-et ott, ahol valóban szükséges.

jsx
// Mérhető optimalizálás: a Child React.memo-ba van csomagolva
const Child = React.memo(({ onClick }) => {
    console.log('A Child újrarenderelődött');
    return <button onClick={onClick}>Click</button>;
});

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

A Dan Abramov — Before You memo() (2024) szerint a useCallback használatának több mint 90%-a nyílt forráskódú projektekben felesleges. A fejlesztők „minden eshetőségre" beburkolnak minden függvényt anélkül, hogy megmérnék a hatást. Alternatíva: ha a gyermekkomponens nehéz, és az újrarenderelése drága — a React.memo + useCallback indokolt. Ha a gyermekkomponens könnyű — az újrarenderelés olcsóbb, mint a függőségek összehasonlítása.

Mikor használd a useCallback-et

Az első forgatókönyv — React.memo. Ha a gyermekkomponens React.memo-ba van csomagolva, és callback függvényt fogad prop-ként, akkor useCallback nélkül a gyermekkomponens a szülő minden renderelésénél újrarajzolódik, még akkor is, ha a saját adatai nem változtak. A useCallback stabilizálja a referenciát, így a React.memo helyesen tudja kihagyni az újrarenderelést.

A második forgatókönyv — useEffect callback-kel a függőségek között. Ha a függvényt a useEffect függőségi tömbjébe adják át, minden új referencia újraindítja az effektet. A useCallback garantálja, hogy a referencia stabil, és az effekt csak a valódi adatok változásakor fut le, nem minden renderelésnél. Ez különösen fontos az előfizetések és kérések esetén.

  • React.memo children — megakadályozza a memoizált gyermekkomponensek újrarenderelését a callback-ek átadásakor.
  • useEffect dependencies — stabilizálja a függvényt az effekt függőségi tömbjében, megelőzve a felesleges újraindításokat.
  • Egyedi hook-ok — ha a hook callback-et fogad, és annak reference equality-jétől függ, a useCallback kötelező.
  • Context value — ha a kontextus value-jában függvényt adnak át, a useMemo a useCallback-kel stabilizálja a referenciát.
jsx
// useCallback stabil useEffect-függőséghez
const fetchData = useCallback(async (id) => {
    const res = await fetch(`/api/${id}`);
    setData(res.data);
}, []); // stabil referencia, soha nem jön újra létre

useEffect(() => {
    fetchData(props.id);
}, [props.id, fetchData]); // az effekt csak a props.id változásakor fut

useCallback vs useMemo

A legfőbb különbség a useCallback és a useMemo között az, hogy melyik mit memoizál. A useCallback a függvényt memoizálja: a useCallback(fn, deps) az fn-t adja vissza (ugyanazt vagy az előző verziót). A useMemo a függvényhívás eredményét memoizálja: a useMemo(() => computeExpensive(a, b), [a, b]) a kiszámított értéket adja vissza, nem a függvényt.

Technikailag a useCallback szintaktikai cukor a useMemo felett: a useCallback(fn, deps) egyenértékű a useMemo(() => fn, deps) kifejezéssel. Ez a szintaxis csak az olvashatóság kedvéért létezik — hogy a fejlesztő világosan lássa, hogy pontosan a függvény kerül memoizálásra, nem pedig az érték. Nincs teljesítménybeli különbség a useCallback és a függvényes useMemo között — ugyanazt a kódot generálják.

HookMemoizálSzintaxisHasználat
useCallbackA függvényt (referenciát)useCallback(fn, deps)Callback-ek gyermekkomponenseknek
useMemoA számítás eredményétuseMemo(() => value, deps)Drága számítások, objektumok memoizálása
jsx
// Ezek egyenértékűek:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);

Gyakori hibák a useCallback-kel

A leggyakoribb hiba — az összes függvény értelmetlen beburkolása useCallback-be React.memo nélkül a gyermekkomponenseken. Ha a gyermekkomponens nincs React.memo-ba csomagolva, akkor minden renderelésnél újrarenderelődik, függetlenül attól, hogy a callback referenciája változik-e vagy sem. A React.memo nélküli useCallback — költség haszon nélkül.

  • useCallback React.memo nélkül — a gyermekkomponens így is újrarenderelődik; az optimalizálás értelmetlen.
  • Elfelejtett függőségek — ha a callback belsejében olyan változót használnak, amely nincs a deps-ben, a callback stale closure-t tartalmaz.
  • Túlzott memoizáció — minden függvény beburkolása, beleértve a console.log-os triviális onClick-eket is.
  • Objektumok és tömbök a függőségekben — a minden renderelésnél keletkező új referencia változásként értelmezendő, a memoizáció haszontalan.
jsx
// ❌ Haszontalan: nincs React.memo a child-on
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // A Child React.memo nélkül is újrarenderelődik

// ❌ Stale closure: hiányzó függőség
const handle = useCallback(() => {
    console.log(count); // a count mindig 0 — stale closure!
}, []);

// ✅ Helyes: tüntesd fel a függőségeket
const handle = useCallback(() => {
    console.log(count);
}, [count]);

A useCallback stale closure problémája úgy oldható meg, hogy a függőségi tömbben feltünteted az összes használt változót. Az exhaustive-deps-t használó eslint-plugin-react-hooks automatikusan ellenőrzi, hogy a callback törzsében lévő összes változó szerepel-e a tömbben. Ha a callback olyan setState-et használ, amely nem változik a renderelések között, nyugodtan feltüntethető a deps-ben — a React garantálja a setState stabilitását.

Gyakran ismételt kérdések

Be kell csomagolni minden függvényt useCallback-be?

Nem. A useCallback csak három esetben bír értelmet: a gyermekkomponens React.memo-ba van csomagolva, a függvényt a useEffect függőségi tömbjében használják, vagy a függvényt olyan egyedi hook-nak adják át, amely a reference equality-től függ. Más esetekben a useCallback csak többletterhelést ad haszon nélkül. A React csapata azt javasolja, hogy előbb optimalizálás nélkül írj, és a profilozás eredményei alapján add hozzá őket.

Melyik a gyorsabb — a useCallback vagy a minden renderelésnél új függvény?

Egyszerű komponenseknél a minden renderelésnél új függvény valamivel gyorsabb, mert a useCallback erőforrásokat költ a függőségek összehasonlítására és a tömb allokációjára. A mély React.memo fákkal rendelkező komponenseknél a useCallback nyer, megakadályozva több ezer gyermekelem újrarenderelését. Mérj és hasonlíts össze, ne találgass — használd a React DevTools Profilert az objektív értékeléshez.

Használható-e a useCallback async függvényekkel?

Igen, a useCallback pontosan ugyanúgy működik az async függvényekkel, mint a szinkronokkal. A hook magát a függvényt memoizálja, az eredményt (Promise) pedig minden hívásnál visszaadja. Az aszinkron függvény a useCallback belsejében gyakori minta a useEffect-ben használt stabil adatbetöltő callback-eknél: const fetchData = useCallback(async (id) => {...}, []).

Hogyan lehet kijavítani a useCallback és a React.memo problémáját?

Használd a React DevTools Profilert — megmutatja, mely komponensek renderelődnek újra és miért. Programozott ellenőrzéshez adj hozzá console.log-ot vagy useWhyDidYouUpdate-ot — egy olyan könyvtárat, amely naplózza az újrarenderelés okát. A fő okok: megváltozott egy prop (beleértve a callback referenciát), megváltozott a state vagy a kontextus. Ha a useCallback nem segít — ellenőrizd, hogy minden függőség helyesen van feltüntetve.

Hogyan adjam át a useCallback-et gyermekkomponensnek React.memo nélkül?

React.memo nélkül is hasznos lehet a useCallback a useMemo-val kombinálva a kontextus value-jához. Ha függvényeket tartalmazó objektumot adsz át a Context.Provider-nek, csomagold az objektum létrehozását useMemo-ba, és minden függvényt useCallback-be. Ez megakadályozza a kontextus összes fogyasztójának újrarenderelését az egyik függvény változásakor. De a callback-ek React.memo nélküli, props-ban való közvetlen átadásánál a useCallback nem jelent előnyt.

Összegzés

  • useCallback — a függvény memoizálására szolgáló hook, amely stabil referenciát ad vissza a függőségek megváltozásáig.
  • React.memo synergy — a useCallback csak a gyermekkomponenseken lévő React.memo-val együtt hatékony.
  • Függőségek összehasonlítása — Object.is segítségével; a deps-ben lévő objektumok/tömbök elrontják a memoizációt.
  • Mérj, ne találgass — csak a profilozóval talált szűk keresztmetszet után add hozzá a useCallback-et.
  • Stable closure — vedd fel az összes használt változót a függőségi tömbbe, különben — stale closure.
  • useCallback vs useMemo — a useCallback a függvényt memoizálja, a useMemo — a számítás eredményét.
  • Feleslegesség — a useCallback valós projektekben való használatának több mint 90%-a korai optimalizálás.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is