De useCallback Hook voor Prestatieoptimalisatie in React
In deze les bekijken we de volgende
hook voor prestatieoptimalisatie
useCallback.
De hook useCallback is vergelijkbaar met de API useMemo,
het verschil is dat de eerste
een waarde cached tussen momenten van hertekening
van het scherm, en de tweede - een callback.
Dit stelt ons in staat om resource-intensieve
functies niet opnieuw uit te voeren wanneer dit niet nodig is en kan
gebruikt worden bij het
doorgeven van een functie
aan child componenten.
Laten we het beter begrijpen met een voorbeeld.
Laten we eerst een component App
maken en daarin een state num aanmaken:
const [num, setNum] = useState(0);
Laten we een knop hebben, bij een klik
waarop num met
1 toeneemt, en een alinea, waarin we
de waarde van num weergeven:
return (
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>kliks: {num}</p>
</div>
);
Stel nu dat we in
App ook een lijst met items
tonen, die we zullen aanvullen
door op een andere knop te drukken. Om de
items van deze lijst op te slaan, maken we
een state items aan:
const [items, setItems] = useState([]);
En dan schrijven we een functie addItem
om ze toe te voegen:
function addItem() {
setItems([...items, 'nieuw item']);
}
Laten we nu de code schrijven voor het weergeven
van de lijstitems en deze in een child
component Items plaatsen, die als
props de array met items en een functie om ze toe te voegen zal ontvangen. Laten we niet vergeten
een console.log toe te voegen, om te zien
wanneer onze Items opnieuw
wordt gerenderd:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items render');
return (
<div>
<h3>Onze items</h3>
{result}
<button onClick={addItem}>item toevoegen</button>
</div>
);
}
export default Items;
Laten we Items aan het einde van de component
App plaatsen en daaraan de array
items en de functie voor het toevoegen
van items addItem doorgeven:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>kliks: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
Laten we nu op de knoppen klikken
en ervoor zorgen dat num groeit en
er nieuwe items aan de lijst worden toegevoegd.
En door de console te openen, zullen we zien dat
onze lijst elke keer opnieuw wordt gerenderd,
zelfs als we op de knop klikken
die num verhoogt.
Als we een kleine lijst hebben, is alles
in orde, maar wat als wordt verwacht dat hij
omvangrijk zal zijn en er nog veel meer in staat?
Geen probleem - zul je zeggen, want in de vorige
les hebben we de API memo bekeken,
om precies onnodige herrenders van componenten
te vermijden.
Laten we dan onze component
Items in memo wikkelen en klaar is kees.
Dit kan trouwens direct
bij het exporteren van Items:
export default memo(Items);
Laten we niet vergeten memo te importeren:
import { memo } from 'react';
Laten we nu de console openen en op de
knoppen klikken. Alle moeite voor niets! We
hebben de component gememoïseerd, maar bij het indrukken
van de knop 'klik' wordt de component
Items nog steeds
elke keer opnieuw gerenderd.
Het ding is dat wanneer de bovenliggende
component opnieuw wordt gerenderd, zijn functies
opnieuw worden aangemaakt - dit geldt ook voor onze
functie addItem, die we doorgeven aan
Items.
Precies op dit moment helpt de hook
useCallback ons. Laten we hem toepassen.
Laten we hem eerst importeren in
App:
import { useCallback } from 'react';
Laten we vervolgens de eenvoudige declaratie van de functie
addItem omzetten in een
Function Expression, als eerste parameter
voor useCallback onze functie als callback specificeren. Als tweede
parameter specificeren we tussen vierkante haakjes
de dependencies - alle reactieve variabelen
die in de functie worden gebruikt, in ons geval
is dit de array items:
const addItem = useCallback(() => {
setItems(() => [...items, 'Nieuw item']);
}, [items]);
Klaar! Op deze manier hebben we de
functie gecached. We klikken weer op de knoppen en
zien dat nu bij het indrukken van de knop
'klik' onze child component niet
opnieuw wordt gerenderd.
Maak een component App, plaats
daarin een alinea met tekst. Maak
een state aan met beginwaarde 'tekst'
en geef deze weer in de alinea. Laat bij een klik
op de alinea aan het einde van de tekst
een uitroepteken verschijnen.
Maak een child component Products,
waarin je een knop hebt om een
nieuw product toe te voegen. Plaats het in App.
Maak in de bovenliggende component een state
aan met een array van producten en een functie voor het toevoegen
van een nieuw product. Geef deze door
als props aan de child, geef daarin de
doorgegeven array weer als een lijst ul.
Geef in Products de tekst
'products render' weer in de console.
Wikkel Products in memo.
Klik op de alinea en de knop. Zorg ervoor,
dat bij het klikken op de alinea de child component
toch opnieuw wordt gerenderd.
Cache de functie voor het toevoegen
van producten, door deze te wikkelen in de hook useCallback.
Klik op de alinea en de knop. Zorg ervoor,
dat bij het klikken op de alinea, de child component
niet meer opnieuw wordt gerenderd.