useCallback og useMemo til ydeevne
Memoizér callback-funktioner med useCallback for at forhindre unødvendige renders af underordnede komponenter, og cache beregnede værdier, der er dyre at udregne, med useMemo.
useCallback og useMemo til ydeevne er en gratis React Native Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i React Native Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. React Native Academy-kurset indeholder 4 lektioner i alt.
Problemet med nye renderinger
Hver gang en komponent renderes igen i React, oprettes alle værdier, der skabes inde i funktionskroppen, på ny. Det omfatter objekter, arrays og vigtigst af alt — funktioner. Hvis en nyoprettet funktion eller værdi gives som prop til en underordnet komponent, ser den underordnede komponent en ny reference og renderes igen, selv når den logiske værdi ikke er ændret.
Hvad er useCallback?
useCallback(fn, deps) returnerer en memoiseret version af callback-funktionen, som kun ændres, hvis en af afhængighederne er ændret. Når du pakker en callback ind i useCallback, bevarer du den samme funktionsreference på tværs af renderinger og forhindrer unødvendige nye renderinger i underordnede komponenter, der modtager den som prop.
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// handlePress is the SAME function reference between renders
// as long as count does not change
const handlePress = useCallback(() => {
console.log('Pressed, count is:', count);
}, [count]);
return <Child onPress={handlePress} />;
}useCallback med React.memo
useCallback er mest effektiv sammen med React.memo på den underordnede komponent. Uden React.memo renderes den underordnede komponent alligevel igen, uanset om prop-referencerne er ens. Kombinationen af React.memo på den underordnede komponent og useCallback på den overordnede callbacks funktion forhindrer nye renderinger, når hverken adfærden eller dataene er ændret.
const ChildButton = React.memo(({ onPress, label }) => (
<Button title={label} onPress={onPress} />
));
function Parent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
// ChildButton will NOT re-render when text changes
const handleCount = useCallback(() => setCount(c => c + 1), []);
return (
<>
<TextInput value={text} onChangeText={setText} />
<ChildButton label='Count' onPress={handleCount} />
</>
);
}Hvad er useMemo?
useMemo(computeFn, deps) memoiserer resultatet af en dyr beregning. React kalder computeFn ved den første rendering og gemmer den returnerede værdi i cachen. Ved efterfølgende renderinger returnerer React den cachede værdi, medmindre en afhængighed er ændret. Det undgår at gentage tunge beregninger ved hver rendering.
import { useMemo } from 'react';
function ProductList({ products, category }) {
// Only recomputes when products or category changes
const filtered = useMemo(
() => products.filter((p) => p.category === category),
[products, category]
);
return <FlatList data={filtered} renderItem={renderItem} />;
}useMemo til stabile objektreferencer
Objekter og arrays, der oprettes direkte i JSX, er nye referencer ved hver rendering. Hvis de gives til en memoiseret underordnet komponent, modarbejder de memoisereringen. Pak dem ind i useMemo for at oprette en stabil reference, der kun ændres, når de underliggende data ændres. Det er især vigtigt for style-arrays og konfigurationsobjekter.
function Chart({ data, color }) {
// New object on every render without useMemo
const chartConfig = useMemo(() => ({
backgroundColor: color,
dataPoints: data.map((d) => d.value),
}), [data, color]);
return <ChartComponent config={chartConfig} />;
}Afhængighedsarrays: Sådan får du dem rigtige
Både useCallback og useMemo kræver korrekte afhængighedsarrays. Medtag alle værdier fra komponentens scope, som bruges inde i den memoiserede funktion eller beregning. Hvis du mangler en afhængighed, bruger den memoiserede værdi en forældet closure; hvis du angiver for mange, udføres beregningen unødvendigt igen. ESLints regel exhaustive-deps hjælper med at håndhæve korrektheden.
// Wrong: missing userId dependency — stale closure bug
const fetchUser = useCallback(() => fetch('/user/' + userId), []);
// Correct: userId is listed
const fetchUser = useCallback(() => fetch('/user/' + userId), [userId]);Hvornår skal useCallback IKKE bruges?
useCallback har en omkostning: React gemmer funktionen i hukommelsen og kontrollerer afhængighedsarrayet ved hver rendering. For enkle handlere, der ikke gives til memoiserede underordnede komponenter, er overheaden ved useCallback større end fordelen. Brug det med omtanke — kun når den underordnede komponent er pakket ind i React.memo, og lighed mellem props har betydning for ydeevnen.
// Unnecessary: Button re-renders anyway; no child is memoized
const handlePress = useCallback(() => setVisible(true), []);
// Fine without useCallback in this case
const handlePress = () => setVisible(true);useMemo til dyre transformationer
Brug useMemo, når en beregning tager mærkbar tid — for eksempel sortering af store arrays, fortolkning af komplekse data eller statistiske beregninger. En tommelfingerregel er: Hvis beregningen tager mere end et millisekund og udføres ved hver rendering, bør du overveje at memoiserere den. Ved banale handlinger, som at lægge to tal sammen, er overheaden ved memoiserering større end selve beregningen.
const sortedAndFiltered = useMemo(() => {
return items
.filter((item) => item.status === selectedStatus)
.sort((a, b) => b.createdAt - a.createdAt)
.slice(0, 100);
}, [items, selectedStatus]);useCallback til renderItem i FlatList
Hvis du pakker renderItem-funktionen i en FlatList ind i useCallback, forhindrer du, at der oprettes en ny funktionsreference ved hver rendering af den overordnede komponent. Ellers ville alle synlige rækker i FlatList blive renderet igen. Det er en af de mest mærkbare ydeevneforbedringer i React Native-apps med mange lister.
const renderItem = useCallback(({ item }) => (
<ProductCard
product={item}
onPress={handleSelectProduct}
/>
), [handleSelectProduct]); // handleSelectProduct also memoized
<FlatList
data={products}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>Måling af effekten
Før du tilføjer memoiserering overalt, skal du måle den faktiske effekt med React DevTools Profiler. Optag en interaktion, se på flammegrafen for at finde komponenter, der renderes unødvendigt igen, og tilføj kun useCallback eller useMemo, hvor profileren viser en reel flaskehals. For tidlig optimering øger kodens kompleksitet uden en målbar fordel.
Sammenligning i korte træk
Husk den vigtigste forskel: useCallback memoiserer en funktion (forhindrer, at funktionsreferencen oprettes igen), mens useMemo memoiserer en beregnet værdi (forhindrer, at en dyr beregning udføres igen). Begge modtager et afhængighedsarray og beregner kun værdien igen, når de angivne afhængigheder ændres.
// useCallback — memoize a function
const fn = useCallback(() => doSomething(a, b), [a, b]);
// useMemo — memoize a computed value
const val = useMemo(() => computeExpensive(a, b), [a, b]);
// Relationship: useCallback(fn, deps) === useMemo(() => fn, deps)Hurtigt tjek
Test din forståelse af useCallback og useMemo til optimering af ydeevnen fra denne lektion.
Opsummering af lektionen
I denne lektion lærte du, at: useCallback memoiserer en funktionsreference for at forhindre unødvendige nye renderinger af underordnede komponenter, useMemo memoiserer en dyr beregnet værdi for at undgå genberegning ved hver rendering, og begge fungerer bedst sammen med React.memo og korrekte afhængighedsarrays. Dernæst ser vi på at skrive brugerdefinerede hooks for at dele tilstandslogik mellem komponenter.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “useCallback og useMemo til ydeevne” gratis?
Ja — alle 3 lektioner i læringssporet React Native Academy, inklusive “useCallback og useMemo til ydeevne”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “useCallback og useMemo til ydeevne”?
Memoizér callback-funktioner med useCallback for at forhindre unødvendige renders af underordnede komponenter, og cache beregnede værdier, der er dyre at udregne, med useMemo. Du øver dig i React Native Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på React Native Academy?
Der kræves ingen tidligere erfaring. React Native Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “useCallback og useMemo til ydeevne”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne React Native Academy-lektion?
Ja. Alle React Native Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- useRef til DOM-noder og ændringsbare værdier
- useReducer til kompleks statelogik
- useCallback og useMemo til ydeevne
- Skrivning af brugerdefinerede hooks