Hook za optimizaciju performansi useCallback u React-u
U ovoj lekciji ćemo razmotriti sledeći
hook za optimizaciju performansi
useCallback.
Hook useCallback je sličan API-ju useMemo,
razlika je u tome što prvi
kešira vrednost između trenutaka ponovnog iscrtavanja
ekrana, a drugi - callback.
Ovo nam omogućava da ne pokrećemo ponovo zahtevne
funkcije kada to nije potrebno i može
se koristiti prilikom
prosljeđivanja funkcije
u komponente-djecu.
Hajde da detaljnije razmotrimo na primeru.
Za početak kreirajmo komponentu App
i napravimo u njoj state num:
const [num, setNum] = useState(0);
Neka imamo dugme, klikom
na koje se num povećava
za 1, i pasus u kome ćemo
prikazati vrednost num:
return (
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>klikovi: {num}</p>
</div>
);
A sada, pretpostavimo da se u
App prikazuje još neki spisak
sa elementima, koji ćemo dopunjavati
klikom na drugo dugme. Za čuvanje
elemenata ovog spiska napravićemo
state items:
const [items, setItems] = useState([]);
I zatim ćemo napisati funkciju addItem
za njihovo dodavanje:
function addItem() {
setItems([...items, 'novi element']);
}
Sada hajde da napišemo kod za prikaz
elemenata spiska i izdvojimo ga u podređenu
komponentu Items, koja će u vidu
props-a primati niz elemenata
i funkciju za njihovo dodavanje. Ne zaboravimo
dodati ispis u konzolu, da bismo videli
kada će se naš Items
ponovo iscrtavati:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Iscrtavanje Items');
return (
<div>
<h3>Naši elementi</h3>
{result}
<button onClick={addItem}>dodaj element</button>
</div>
);
}
export default Items;
Postavimo Items na kraj komponente
App i prosledićemo mu niz
items i funkciju za dodavanje
elemenata addItem:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>klik</button>
<p>klikovi: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
A sada hajde da klikćemo na dugmad
i uverimo se da se num povećava i
da se novi elementi dodaju u spisak.
A otvorivši konzolu, videćemo da
se naš spisak ponovo iscrtava svaki
put, čak i ako kliknemo na dugme,
koje povećava num.
Ako imamo mali spisak, onda je sve
u redu, a ako se pretpostavlja da će on
biti obiman i da tu ima još mnogo toga?
Nije problem - reći ćete, jer smo na prošlom
času razmotrili API memo,
da bismo izbegli nepotrebna ponovna iscrtavanja
komponente.
Pa hajde da obmotamo našu komponentu
Items u memo i gotovo.
Usput, ovo se može uraditi direktno
prilikom eksporta Items:
export default memo(Items);
Ne zaboravimo da importujemo memo:
import { memo } from 'react';
A sada otvorimo konzolu i hajde da klikćemo
na dugmad. Sav trud uzaludan! Mi
smo memoizirali komponentu, ali prilikom klika
na dugme 'klik' komponenta
Items se i dalje
ponovo iscrtava svaki put.
Stvar je u tome, da kada se roditeljska
komponenta ponovo iscrtava, njene funkcije
se ponovo kreiraju - to se odnosi i na našu
funkciju addItem, koju prosleđujemo u
Items.
Upravo u ovom trenutku će nam pomoći hook
useCallback. Hajde da ga primenimo.
Za početak importujmo ga u
App:
import { useCallback } from 'react';
Zatim transformišimo jednostavnu deklaraciju funkcije
addItem u
Function Expression, navedimo kao
prvi parametar za useCallback
našu funkciju u vidu callback-a. Drugim
parametrom u uglastim zagradama navedimo
zavisnosti - sve reaktivne promenljive,
koje učestvuju u funkciji, u našem slučaju
to je niz items:
const addItem = useCallback(() => {
setItems(() => [...items, 'Novi element']);
}, [items]);
Gotovo! Na taj način smo keširali
funkciju. Ponovo klikćemo na dugmad i
vidimo da sada prilikom klika na dugme
'klik' naša podređena komponenta ne
iscrtava se ponovo.
Kreirajte komponentu App, postavite
u nju pasus sa tekstom. Napravite
state sa početnom vrednošću 'tekst'
i prikažite ga u pasusu. Neka se klikom
na pasus na kraju teksta
doda uzvičnik.
Kreirajte podređenu komponentu Products,
u kojoj ćete imati dugme za dodavanje
novog proizvoda. Postavite je u App.
U roditeljskoj komponenti kreirajte state
sa nizom proizvoda i funkciju dodavanja
novog proizvoda. Prosledite ih u
kao props u podređenu, prikažite u njoj
prosledjeni niz u vidu spiska ul.
U Products prikažite u konzoli tekst
'iscrtavanje products'.
Obmotajte Products u memo.
Klikćite na pasus i dugme. Uverite se,
da se pri kliku na pasus podređena komponenta
i dalje ponovo iscrtava.
Keširajte funkciju za dodavanje
proizvoda, obmotavši je u hook useCallback.
Klikćite na pasus i dugme. Uverite se,
da se pri kliku na pasus, podređena komponenta
više ne iscrtava ponovo.