Hook-ul de optimizare a performanței useCallback în React
În această lecție vom analiza următorul
hook pentru optimizarea performanței
useCallback.
Hook-ul useCallback este similar cu API-ul useMemo,
diferența constă în faptul că primul
cachează valoarea între momentele de re-randare
ale ecranului, iar al doilea - un callback.
Aceasta ne permite să nu relansăm funcțiile
care consumă multe resurse
când acest lucru nu este necesar și poate
fi utilizat la
transmiterea unei funcții
în componentele copil.
Să înțelegem mai detaliat cu un exemplu.
Pentru început, să creăm un component App
și să definim în el starea num:
const [num, setNum] = useState(0);
Să avem un buton, la click
pe care num crește
cu 1, și un paragraf, în care
vom afișa valoarea num:
return (
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
</div>
);
Acum, să presupunem că în
App se afișează încă o listă
cu elemente, pe care o vom completa
la apăsarea unui alt buton. Pentru stocarea
elementelor acestei liste vom defini
starea items:
const [items, setItems] = useState([]);
Apoi vom scrie funcția addItem
pentru adăugarea lor:
function addItem() {
setItems([...items, 'new item']);
}
Acum să scriem codul pentru afișarea
elementelor listei și să-l mutăm în componentul
copil Items, care va primi ca props
array-ul de elemente
și funcția pentru adăugarea acestora. Să nu uităm
să adăugăm o afișare în consolă, pentru a vedea
când Items va fi
re-randat:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items render');
return (
<div>
<h3>Our items</h3>
{result}
<button onClick={addItem}>add item</button>
</div>
);
}
export default Items;
Să plasăm Items la sfârșitul componentului
App și să-i transmitem array-ul
items și funcția pentru adăugarea
elementelor addItem:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
Acum să apăsăm pe butoane
și să ne convingem că num crește și
elementele noi se adaugă în listă.
Iar deschizând consola, vom vedea că
lista noastră se re-randează de fiecare
dată, chiar dacă apăsăm pe butonul
care mărește num.
Dacă avem o listă mică, atunci totul
este în regulă, dar dacă se presupune că aceasta
va fi voluminoasă și conține multe alte lucruri?
Nici o problemă - veți spune, pentru că în lecția precedentă
am analizat API-ul memo,
tocmai pentru a evita re-randările inutile
ale componentului.
Deci, să împachetăm componentul nostru
Items în memo și gata.
Apropo, acest lucru poate fi făcut direct
la exportarea Items:
export default memo(Items);
Să nu uităm să importăm memo:
import { memo } from 'react';
Acum să deschidem consola și să apăsăm
pe butoane. Toate eforturile în zadar! Am
memoizat componentul, dar la apăsarea
butonului 'click' componentul
Items tot
se re-randează de fiecare dată.
Problema este că atunci când componentul
părinte se re-randează, funcțiile sale
sunt recreate din nou - aceasta se referă și la funcția noastră
addItem, pe care o transmitem în
Items.
Exact în acest moment ne va ajuta hook-ul
useCallback. Să îl aplicăm.
Pentru început, să-l importăm în
App:
import { useCallback } from 'react';
Apoi, să transformăm declarația simplă a funcției
addItem în
Expression Function, să indicăm ca
prim parametru pentru useCallback
funcția noastră sub formă de callback. Al doilea
parametru, în paranteze pătrate, îl vom indica
dependințele - toate variabilele reactive,
care participă în funcție, în cazul nostru
acesta este array-ul items:
const addItem = useCallback(() => {
setItems(() => [...items, 'New item']);
}, [items]);
Gata! Astfel am cache-uit
funcția. Apăsăm din nou pe butoane și
vedem că acum la apăsarea butonului
'click' componentul nostru copil nu
se re-randează.
Creați un component App, plasați
în el un paragraf cu text. Definiți
o stare cu valoarea inițială 'text'
și afișați-o în paragraf. La click
pe paragraf, să i se adauge la sfârșitul textului
un semn de exclamare.
Creați un component copil Products,
în care veți avea un buton pentru adăugarea
unui produs nou. Plasați-l în App.
În componentul părinte, creați o stare
cu un array de produse și o funcție de adăugare
a unui produs nou. Transmiteți-le
ca props în componentul copil, afișați în acesta
array-ul transmis sub forma unei liste ul.
În Products afișați în consolă textul
'products render'.
Împachetați Products în memo.
Apăsați pe paragraf și buton. Asigurați-vă
că la click pe paragraf, componentul copil
se re-randează oricum.
Cache-uiți funcția pentru adăugarea
produselor, împachetând-o în hook-ul useCallback.
Apăsați pe paragraf și buton. Asigurați-vă
că la click pe paragraf, componentul copil
nu se mai re-randează.