useCallback Hook til Performanceoptimering i React
I denne lektion vil vi se på følgende
hook til performanceoptimering:
useCallback.
Hooket useCallback ligner API'et useMemo,
forskellen ligger i, at den første
cacher en værdi mellem genrendringer,
mens den anden cacher en callback.
Dette giver os mulighed for ikke at genkøre ressourcekrævende
funktioner, når det ikke er nødvendigt, og det kan
bruges ved
overførsel af en funktion
til underordnede komponenter.
Lad os undersøge det nærmere med et eksempel.
Lad os først oprette en komponent App
og oprette en state num i den:
const [num, setNum] = useState(0);
Lad os have en knap, ved klik
på hvilken num øges
med 1, og et afsnit, hvor vi
vil udskrive værdien af num:
return (
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>kliks: {num}</p>
</div>
);
Lad os nu antage, at vi i
App også viser en liste
med elementer, som vi vil tilføje til
ved at klikke på en anden knap. For at gemme
elementerne på denne liste opretter vi
state items:
const [items, setItems] = useState([]);
Og derefter skriver vi funktionen addItem
for at tilføje dem:
function addItem() {
setItems([...items, 'nyt element']);
}
Lad os nu skrive koden til at vise
listeelementerne og flytte den til en underordnet
komponent Items, som via props
vil modtage et array af elementer
og en funktion til at tilføje dem. Lad os ikke glemme
at tilføje en konsoludskrift, så vi kan se
hvornår vores Items bliver
genrendret:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items genrendres');
return (
<div>
<h3>Vores elementer</h3>
{result}
<button onClick={addItem}>tilføj element</button>
</div>
);
}
export default Items;
Lad os placere Items i slutningen af komponenten
App og sende arrayet
items og funktionen til at tilføje
elementer addItem til den:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>kliks: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
Lad os nu klikke på knapperne
og sikre os, at num vokser og
at nye elementer tilføjes til listen.
Hvis vi åbner konsollen, vil vi se, at
vores liste genrendres hver
gang, selvom vi klikker på knappen,
der øger num.
Hvis vores liste er lille, er alt
i orden, men hvad nu hvis den forventes at være
omfangsrig, og der er mange andre ting?
Intet problem - siger du måske, for i den forrige
lektion så vi på API'et memo,
for netop at undgå unødvendige genrendringer
af komponenten.
Så lad os indpakke vores komponent
Items i memo, så er den ged barberet.
Det kan for øvrigt gøres direkte
ved eksport af Items:
export default memo(Items);
Lad os ikke glemme at importere memo:
import { memo } from 'react';
Lad os nu åbne konsollen og klikke på
knapperne. Alle anstrengelser var forgæves! Vi
har memoiseret komponenten, men ved klik
på knappen 'klik' genrendres komponenten
Items alligevel hver gang.
Grunden er, at når den forældrekomponent
genrendres, bliver dens funktioner
genskabt på ny - det gælder også vores
funktion addItem, som vi sender til
Items.
Netop på dette tidspunkt kan hooket
useCallback hjælpe os. Lad os anvende
det. Til at starte med importerer vi det til
App:
import { useCallback } from 'react';
Derefter omskriver vi den simple funktionserklæring
addItem til et
Function Expression, angiver som
første parameter til useCallback
vores funktion som en callback. Som anden
parameter i firkantede parenteser angiver vi
afhængighederne - alle de reaktive variable,
der deltager i funktionen, i vores tilfælde
er det arrayet items:
const addItem = useCallback(() => {
setItems(() => [...items, 'Nyt element']);
}, [items]);
Klar! På denne måde har vi cachet
funktionen. Vi klikker igen på knapperne og
ser, at nu, når vi klikker på knappen
'klik', bliver vores underordnede komponent ikke
genrendret.
Opret en komponent App, placer
et afsnit med tekst i den. Opret
en state med startværdien 'tekst'
og udskriv den i afsnittet. Lad det ved klik
på afsnittet tilføje et udråbstegn
til slutningen af teksten.
Opret en underordnet komponent Products,
hvor du har en knap til at tilføje
et nyt produkt. Placer den i App.
Opret i den forældrekomponent en state
med et array af produkter og en funktion til at tilføje
et nyt produkt. Send dem som
props til den underordnede, udskriv i den
det sendte array som en liste ul.
I Products skal du udskrive i konsollen teksten
'products render'.
Pak Products ind i memo.
Klik på afsnittet og knappen. Sikr dig,
at ved klik på afsnittet genrendres den underordnede komponent
alligevel.
Cache funktionen til at tilføje
produkter ved at indpakke den i hooket useCallback.
Klik på afsnittet og knappen. Sikr dig,
at ved klik på afsnittet genrendres den underordnede komponent
ikke længere.