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:

App.jsxreturn (
  <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:

App.jsxconst [isGreen, setIsGreen] = useState(false);

Dodajmy do atrybutu style nagłówka warunek zmiany koloru nagłówkowi i dodajmy obsługę kliknięcia:

App.jsx<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:

App.jsxconst [num, setNum] = useState(0);

Dodajmy obsługę kliknięcia w przycisk:

App.jsx<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:

App.jsxconst result = square(num);

function square(num) {
  return num * num;
}

Wyświetlmy result w tekście przycisku:

App.jsx<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:

App.jsxfunction 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ę:

App.jsxconst 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.

Задание 1

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.

Задание 2

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.

Задание 3

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.

Задание 4

Popraw sytuację, opakowując wolno działającą funkcję triple w useMemo.