useCallback — viktiga begrepp, hooken för memoization av funktioner i React

Författare: IT Sectr Publicerad: 2026-07-04 Lästid: 9 min

useCallback — är en React-hook som returnerar en memoiserad version av funktionen, som inte ändras mellan renderningar så länge dess beroenden inte ändras. Till skillnad från vanlig deklaration av en funktion inuti komponenten (som skapar en ny funktion vid varje render) stabiliserar useCallback referensen till funktionen, vilket förhindrar onödiga re-renders av barnkomponenter som optimerats genom React.memo. Enligt React Documentation (2025) är useCallback endast användbar i kombination med React.memo eller hooks som beror på en stabil referens.

Det viktigaste

  • useCallback — hook för memoization av funktioner, som bevarar referensen mellan renderningar.
  • React.memo — useCallback är endast effektiv i kombination med React.memo för att förhindra re-renders.
  • Beroenden — funktionen återskapas endast när angivna värden i arrayen ändras.
  • Stabil referens — useCallback garanterar att referensen till funktionen inte ändras i onödan.
  • Överanvänd inte — överflödigt useCallback utan React.memo försämrar prestandan.

Vad är useCallback i React

useCallback — är en hook som lades till i React 16.8 och som memoiserar funktionen: den returnerar samma referens tills beroendena ändras. Utan useCallback skapar varje deklaration av en funktion inuti komponenten ett nytt funktionsobjekt vid varje render. För primitiva värden är detta omärkbart, men när sådana callbacks skickas till barnkomponenter som optimerats genom React.memo orsakar varje ny referens en re-render av barnkomponenten.

Syntaxmässigt är useCallback ekvivalent med useMemo för funktioner: useCallback(fn, deps) — är en förkortning för useMemo(() => fn, deps). React lagrar den memoiserade funktionen i den interna lagringen av fiber-noden och jämför beroendena vid varje render. Om beroendena inte har ändrats (Object.is för varje element) returneras den tidigare funktionen.

Enligt React Documentation — useCallback (2025) behöver du inte linda in varje funktion i useCallback. Hooken har sitt pris: anrop av hooken, jämförelse av beroenden och minnesallokering för beroendearrayen. Om komponenten är enkel och inte har djupa träd med React.memo kommer useCallback bara att sakta ner applikationen. Optimering måste vara mätbar, inte intuitiv.

jsx
import { useCallback } from 'react';

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

    // Stabil referens — samma funktion tills deps ändras
    const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

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

Hur fungerar memoization av funktioner

Memoization i useCallback bygger på cachelagring av resultatet av funktionsanropet. React bevarar den closure som skapades vid den första rendern och returnerar den vid efterföljande renderningar så länge beroendena förblir oförändrade. Inuti fiber-noden skapar varje useCallback-anrop en nod i hookarnas länkade lista, där tidigare beroenden och det memoiserade värdet lagras.

Processen för att jämföra beroenden sker strikt genom Object.is — det är en ytlig jämförelse, utan djup kontroll av objekt eller arrayer. Om det finns ett objekt eller en array i beroendena kommer den nya referensen vid varje render att betraktas som en ändring. Därför måste du i beroendearrayen skicka primitiva värden eller stabila referenser (till exempel från useRef eller useMemo).

Enligt React Core Team — Optimization Guide (2024) omfattar kostnaden för memoization tre komponenter: allokering av beroendearrayen vid varje render, genomgång och jämförelse av elementen genom Object.is samt potentiell overhead från garbage collection vid återskapande. För en komponent med hundratals useCallback-inpackningar kan detta bli märkbart — därför är selektivitet i användningen av hooken avgörande.

ScenarioUtan useCallbackMed useCallback
Skapande av funktionNy vid varje renderSamma vid stabila deps
Överföring till React.memoBarnet re-rendrarBarnet re-rendrar inte
I useEffect-arrayenEffekten startas omEffekten är stabil
OverheadMinimalJämförelse av beroenden + minne

useCallback och prestanda

Det finns en utbredd myt om att useCallback automatiskt förbättrar prestandan. I verkligheten saktar useCallback i isolering (utan React.memo) till och med ner applikationen något på grund av kostnaden för att jämföra beroenden. Hooken ger verklig nytta endast i tre scenarier: förhindrande av re-renders av React.memo-komponenter, stabilitet för callbacks i useEffect och överföring till custom hooks som beror på reference equality.

Regeln är enkel: tills du har hittat ett prestandaproblem genom React DevTools Profiler — använd inte useCallback. React-teamet har upprepade gånger betonat att för tidig optimering är roten till allt ont. Skriv först ren kod utan memoization, mät, hitta flaskhalsen i profileraren och lägg först därefter till useCallback där det verkligen behövs.

jsx
// Mätbar optimering: Child är inlindad i React.memo
const Child = React.memo(({ onClick }) => {
    console.log('Child re-rendrade');
    return <button onClick={onClick}>Click</button>;
});

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

Enligt Dan Abramov — Before You memo() (2024) är över 90 % av användningarna av useCallback i open source-projekt överflödiga. Utvecklare lindar in varje funktion "för säkerhets skull" utan att mäta effekten. Alternativ: om barnkomponenten är tung och dess re-render är dyr — är React.memo + useCallback motiverade. Om barnkomponenten är lätt — är en re-render billigare än att jämföra beroenden.

När ska du använda useCallback

Första scenariot — React.memo. Om barnkomponenten är inlindad i React.memo och tar emot en callback-funktion som prop, kommer barnkomponenten utan useCallback att ritas om vid varje render av föräldern, även om dess egna data inte har ändrats. useCallback stabiliserar referensen och React.memo kan korrekt hoppa över re-rendern.

Andra scenariot — useEffect med callback i beroendena. Om funktionen skickas till useEffects beroendearray kommer varje ny referens att starta om effekten. useCallback garanterar att referensen är stabil och att effekten endast körs när de faktiska data ändras, inte vid varje render. Detta är särskilt viktigt för prenumerationer och förfrågningar.

  • React.memo children — förhindrar re-renders av memoiserade barnkomponenter vid överföring av callbacks.
  • useEffect dependencies — stabiliserar funktionen i effektens beroendearray och förhindrar onödiga omstarter.
  • Custom hooks — om hooken tar emot en callback och beror på dess reference equality är useCallback obligatorisk.
  • Context value — om en funktion skickas i kontextens value stabiliserar useMemo tillsammans med useCallback referensen.
jsx
// useCallback för stabil useEffect-beroende
const fetchData = useCallback(async (id) => {
    const res = await fetch(`/api/${id}`);
    setData(res.data);
}, []); // stabil referens, återskapas aldrig

useEffect(() => {
    fetchData(props.id);
}, [props.id, fetchData]); // effekten körs endast när props.id ändras

useCallback vs useMemo

Den främsta skillnaden mellan useCallback och useMemo är vad var och en memoiserar. useCallback memoiserar funktionen: useCallback(fn, deps) returnerar fn (samma eller tidigare version). useMemo memoiserar resultatet av funktionsanropet: useMemo(() => computeExpensive(a, b), [a, b]) returnerar det beräknade värdet, inte funktionen.

Tekniskt sett är useCallback syntaktiskt socker ovanpå useMemo: useCallback(fn, deps) är ekvivalent med useMemo(() => fn, deps). Denna syntax finns endast för läsbarhetens skull — så att utvecklaren tydligt ser att det är just funktionen som memoiseras, inte värdet. Det finns ingen skillnad i prestanda mellan useCallback och useMemo med funktion — de genererar samma kod.

HookMemoiserarSyntaxAnvändning
useCallbackFunktionen (referensen)useCallback(fn, deps)Callbacks för barnkomponenter
useMemoResultatet av beräkningenuseMemo(() => value, deps)Dyra beräkningar, memoization av objekt
jsx
// Dessa är ekvivalenta:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);

Vanliga misstag med useCallback

Det vanligaste misstaget — att meningslöst linda in alla funktioner i useCallback utan React.memo på barnkomponenter. Om barnkomponenten inte är inlindad i React.memo kommer den ändå att re-rendras vid varje render av föräldern, oavsett om callbackens referens ändras eller inte. useCallback utan React.memo — kostnad utan nytta.

  • useCallback utan React.memo — barnkomponenten re-rendrar ändå; optimeringen är meningslös.
  • Glömda beroenden — om en variabel som inte finns i deps används inuti callbacken innehåller callbacken en stale closure.
  • Överdriven memoization — att linda in varje funktion, inklusive triviala onClick med console.log.
  • Objekt och arrayer i beroendena — den nya referensen vid varje render betraktas som en ändring, memoizationen är värdelös.
jsx
// ❌ Värdelös: utan React.memo på child
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child re-rendrar ändå utan React.memo

// ❌ Stale closure: saknat beroende
const handle = useCallback(() => {
    console.log(count); // count är alltid 0 — stale closure!
}, []);

// ✅ Korrekt: inkludera beroenden
const handle = useCallback(() => {
    console.log(count);
}, [count]);

Problemet med stale closure i useCallback löses genom att ange alla använda variabler i beroendearrayen. eslint-plugin-react-hooks med exhaustive-deps kontrollerar automatiskt att alla variabler från callback-kroppen finns i arrayen. Om callbacken använder setState, som inte ändras mellan renderningar, kan den säkert anges i deps — React garanterar stabiliteten för setState.

Vanliga frågor

Måste jag linda in varje funktion i useCallback?

Nej. useCallback är endast meningsfullt i tre fall: barnkomponenten är inlindad i React.memo, funktionen används i useEffects beroendearray eller funktionen skickas till en custom hook som beror på reference equality. I övriga fall tillför useCallback overhead utan nytta. React-teamet rekommenderar att du först skriver utan optimeringar och lägger till dem baserat på resultaten av profilering.

Vad är snabbast — useCallback eller en ny funktion vid varje render?

För enkla komponenter är en ny funktion vid varje render något snabbare, eftersom useCallback förbrukar resurser på att jämföra beroenden och allokera arrayer. För komponenter med djupa React.memo-träd vinner useCallback, eftersom det förhindrar re-renders av tusentals element. Mät och jämför, gissa inte — använd React DevTools Profiler för en objektiv bedömning.

Kan jag använda useCallback med async-funktioner?

Ja, useCallback fungerar med async-funktioner precis som med synkrona. Hooken memoiserar själva funktionen, och resultatet (Promise) returneras varje gång vid anropet. En asynkron funktion inuti useCallback är ett vanligt mönster för stabila callbacks för datahämtning som används i useEffect: const fetchData = useCallback(async (id) => {...}, []).

Hur felsöker jag problemet med useCallback och React.memo?

Använd React DevTools Profiler — den visar vilka komponenter som re-rendras och varför. För programmeringsbaserad kontroll lägg till console.log eller useWhyDidYouUpdate — ett bibliotek som loggar orsaken till re-rendern. De främsta orsakerna: en prop har ändrats (inklusive callback-referensen), state eller kontext har ändrats. Om useCallback inte hjälper — kontrollera att alla beroenden är korrekt angivna.

Hur skickar jag useCallback till en barnkomponent utan React.memo?

Även utan React.memo kan useCallback vara användbar i kombination med useMemo för kontextens value. Om du skickar ett objekt med funktioner till Context.Provider, linda in skapandet av objektet i useMemo och varje funktion i useCallback. Detta förhindrar re-renders av alla konsumenter av kontexten när en av funktionerna ändras. Men för direkt överföring av callbacks i props utan React.memo ger useCallback ingen nytta.

Slutsatser

  • useCallback — hook för memoization av funktioner, som returnerar en stabil referens tills beroendena ändras.
  • React.memo synergy — useCallback är endast effektiv i kombination med React.memo på barnkomponenter.
  • Jämförelse av beroenden — genom Object.is; objekt/arrayer i deps förstör memoizationen.
  • Mät, gissa inte — lägg till useCallback först efter att du hittat en flaskhals genom profileraren.
  • Stable closure — inkludera alla använda variabler i beroendearrayen, annars — stale closure.
  • useCallback vs useMemo — useCallback memoiserar funktionen, useMemo — resultatet av beräkningen.
  • Överflöd — över 90 % av användningarna av useCallback i verkliga projekt är för tidig optimering.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också