Suorituskyvyn optimointihook useCallback Reactissa
Tässä oppitunnissa tarkastelemme seuraavaa
suorituskyvyn optimointiin tarkoitettua
hookia useCallback.
Hook useCallback on samankaltainen kuin useMemo-API,
ero on siinä, että ensimmäinen
välimuististaa arvon uudelleenrenderöintien välillä
kun taas toinen - takaisinkutsufunktion.
Tämä mahdollistaa sen, että emme käynnistä uudelleen resurssiä kuluttavia
funktioita, kun sitä ei vaadita, ja sitä voidaan
käyttää, kun
funktio välitetään
alikomponenteille.
Selvitetään tarkemmin esimerkin avulla.
Aluksi luomme komponentin App
ja luomme siihen tilan num:
const [num, setNum] = useState(0);
Olkoon meillä painike, jota klikkaamalla
num kasvaa
yhdellä 1, sekä kappale, johon
tulostamme num-arvon:
return (
<div>
<button onClick={() => setNum(num + 1)}>klikkaa</button>
<p>klikkauksia: {num}</p>
</div>
);
Oletetaan nyt, että
App-komponentissa näytetään myös jokin lista
alkioista, jota täydennämme toista painiketta painamalla.
Tämän listan alkioiden tallentamiseen luomme
tilan items:
const [items, setItems] = useState([]);
Kirjoitamme sitten funktion addItem
niiden lisäämiseksi:
function addItem() {
setItems([...items, 'new item']);
}
Kirjoitetaan nyt koodi listan alkioiden näyttämiseksi
ja siirretään se alikomponenttiin Items, joka propsien
muodossa saa alkioiden taulukon
ja funktion niiden lisäämiseksi. Älä unohda
lisätä konsolitulostusta nähdäksesi
koska Items -komponenttiamme
renderöidään uudelleen:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items renderöityy');
return (
<div>
<h3>Meidän alkionsa</h3>
{result}
<button onClick={addItem}>lisää alkio</button>
</div>
);
}
export default Items;
Sijoitetaan Items App-komponentin loppuun
ja annetaan sille taulukko
items ja funktio alkioiden lisäämiseksi addItem:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>klikkaa</button>
<p>klikkauksia: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
Kokeillaan nyt painaa painikkeita
ja varmistetaan, että num kasvaa ja
uudet alkiot lisätään listaan.
Avaamalla konsolin, näemme, että
listamme renderöityy uudelleen joka
kerta, vaikka klikkaisimme painiketta,
joka kasvattaa num-arvoa.
Jos listamme on pieni, kaikki on
kunnossa, mutta entä jos oletetaan, että se
on laaja ja siinä on paljon muutakin?
Ei hätää - sanot varmaan, sillä edellisellä
tunnilla tarkastelimme memo-API:a
juuri tarpeettomien komponenttien uudelleenrenderöintien
välttämiseksi.
Kääritään siis Items-komponenttimme memo:oon ja valmista.
Tämä voidaan tehdä suoraan
Items:n viennin yhteydessä:
export default memo(Items);
Älä unohda importata memo:
import { memo } from 'react';
Avataan nyt konsoli ja painellaan
painikkeita. Kaikki ponnistelut turhaan!
Memoimasimme komponentin, mutta kun painamme
painiketta 'click', Items-komponentti
renderöityy silti uudelleen joka kerta.
Asia on siinä, että kun yläkomponentti
renderöityy uudelleen, sen funktiot
luodaan uudelleen - tämä koskee myös
addItem-funktiotamme, jonka välitämme
Items:lle.
Juuri tässä vaiheessa hook
useCallback auttaa meitä.
Käytetään sitä. Aluksi importataan se
App:ään:
import { useCallback } from 'react';
Muutetaan sitten yksinkertainen funktion
addItem määrittely
Funktioilmaisuksi, asetetaan ensimmäiseksi
parametriksi useCallback:lle
funktiomme takaisinkutsuna. Toisena
parametrina hakasulkeissa määritämme
riippuvuudet - kaikki reaktiiviset muuttujat,
jotka osallistuvat funktioon, meidän tapauksessamme
taulukko items:
const addItem = useCallback(() => {
setItems(() => [...items, 'New item']);
}, [items]);
Valmista! Näin olemme välimuististaneet
funktion. Painellaan uudelleen painikkeita ja
näemme, että nyt painettaessa painiketta
'click' alikomponenttiamme ei
renderöidy uudelleen.
Luo komponentti App, aseta
siihen kappale tekstillä. Luo
tila alkuarvolla 'text'
ja tulosta se kappaleeseen. Kun
kappaletta klikataan, sen loppuun
lisätään huutomerkki.
Luo alikomponentti Products,
jossa on painike uuden tuotteen lisäämiseksi.
Sijoita se App:ään.
Yläkomponentissa Luo tila
tuotetaulukolla ja funktio uuden
tuotteen lisäämiseksi. Välitä ne
propsina alikomponenttiin, tulosta siinä
annettu taulukko listana ul.
Products-komponentissa tulosta konsoliin teksti
'products render'.
Kääri Products memo:oon.
Klikkaile kappaletta ja painiketta. Varmista,
että kappaletta klikatessa alikomponentti
renderöityy silti uudelleen.
Välimuistista tuotteiden lisäämisfunktio
käärimällä se useCallback-hookiin.
Klikkaile kappaletta ja painiketta. Varmista,
että kappaletta klikatessa, alikomponentti
ei enää renderöidy uudelleen.