Hook optymalizacji wydajności useMemo w React
Pierwszym hookiem do optymalizacji
wydajności, który rozważymy,
jest useMemo.
Ten hook pomaga buforować wyniki operacji wymagających dużych zasobów między momentami ponownego renderowania ekranu i odpowiednio może pomóc uniknąć zbędnych, obszernych obliczeń. Takie buforowanie nazywa się również memoisacją.
Zobaczmy, jak to działa. Stwórzmy
komponent z przyciskiem i
nagłówkiem h3:
return (
<div>
<h3>Text</h3>
<button>click</button>
</div>
);
A teraz zróbmy tak, aby po kliknięciu
w nagłówek jego kolor zmieniał się z pomarańczowego
na zielony i z powrotem. Na początek
stwórzmy stan isGreen:
const [isGreen, setIsGreen] = useState(false);
Dodajmy do atrybutu style nagłówka
warunek zmiany koloru nagłówkowi i
dodajmy obsługę kliknięcia:
<h3 onClick={() => setIsGreen(!isGreen)}
style={{ color: isGreen ? 'green' : 'orangered' }}
>Text</h3>
Niech będzie też jakaś wartość, która będzie zwiększać się po kliknięciu w nasz przycisk o jeden. Stwórzmy dla niego stan:
const [num, setNum] = useState(0);
Dodajmy obsługę kliknięcia w przycisk:
<button onClick={() => setNum(num + 1)}>
clicks
</button>
Niech będzie też jakaś funkcja
square, która będzie zwracać
kwadrat wartości num. Wynik
wywołania funkcji będziemy zapisywać w
zmiennej result:
const result = square(num);
function square(num) {
return num * num;
}
Wyświetlmy result w tekście przycisku:
<button onClick={() => setNum(num + 1)}>
clicks: {result}
</button>
W rezultacie otrzymaliśmy następujące:
po kliknięciu w przycisk zmienia się wartość
num, która następnie jest podnoszona
do kwadratu, a po kliknięciu w nagłówek
zmienia się kolor nagłówka.
Mamy bardzo mały komponent, wszystko działa szybko, pomimo tego, że po kliknięciu w nagłówek w celu zmiany jego koloru cały komponent renderuje się od nowa, odpowiednio ponownie odbywają się obliczenia, które są powiązane z przyciskiem, i to nawet wtedy, gdy go nie dotykaliśmy. A teraz wyobraźcie sobie, gdyby nasze obliczenia były obszerne i wszystko byłoby przeliczane od nowa za każdym razem.
Uczyńmy naszą funkcję nieco cięższą, teraz będzie myśleć trochę dłużej. W ten sposób zasymulujemy długie obliczenia:
function square(num) {
let startTime = performance.now();
while (performance.now() - startTime < 500) {
// Po prostu nic nie rób ...
}
return num * num;
}
Klikajcie teraz w nagłówek. Okazuje się,
że teraz z powodu długiej pracy funkcji
square (a przecież przycisku nie dotykamy)
musimy czekać całą wieczność, aby
nagłówek zmienił kolor!
Tutaj z pomocą przychodzi nam hook
useMemo. Aby tego dokonać, musimy pierwszym
parametrem przekazać funkcję, obliczającą
wartość, którą chcemy zbuforować,
ta funkcja powinna być czysta i nie
przyjmować żadnych parametrów. A drugim
parametrem - zależności w kwadratowych
nawiasach, innymi słowy, wszystkie reaktywne
wartości, które uczestniczą w kodzie
funkcji. W ten sposób, w result
wpiszemy teraz taką konstrukcję:
const result = useMemo(() => square(num), [num]);
Ponownie klikajmy w nagłówek. Teraz,
jeśli nie dotykamy przycisku z obliczeniami
i nie zmieniamy w ten sposób wartości stanu
num, to nic nie jest przeliczane,
i React wyświetla zbuforowaną wartość
w przycisku, dlatego nasz nagłówek
szybciutko zmienia swój kolor.
Stwórz komponent App, umieść
w nim akapit. Stwórz stan text
z wartością początkową 'react',
niech wartość stanu jest wyświetlana
jako tekst akapitu. Niech po kliknięciu
w akapit, na koniec jego tekstu dodawany jest
znak wykrzyknika.
Stwórz jeszcze jeden stan num, z
wartością początkową 0. Umieść w
App jeszcze jeden akapit. Zrób tak,
aby przy kliknięciu w niego num
zwiększała się o 1.
A teraz dodaj do App funkcję
triple, która jako
parametr przyjmuje num i
zwraca jego potrojoną wartość.
Umieść wynik wywołania funkcji
w zmiennej result. Wyświetl
result jako tekst drugiego
akapitu. Klikaj na przemian w akapity,
zauważ, jak wolno dodają się
znaki wykrzyknika.
Popraw sytuację, opakowując wolno działającą
funkcję triple w useMemo.