Kako izbjeći ovu zamku izvedbe React Hooks

React Kuke obećavaju da će izbjeći prekomjerne troškove komponenti klase, a pritom će vam pružiti iste prednosti. Na primjer, omogućuju nam pisanje značajnih funkcionalnih komponenti bez brige o pohranjivanju stanja u instancu klase.

Međutim, pisanje izvanrednih komponenti s Kukama zahtijeva oprez. Postoji suptilna razlika između toga kako se stanje inicijalizira u konstruktoru komponente klase i načina na koji ga inicijalizira kuka useState. Programeri koji već razumiju komponente klase i misle na Kuke jednostavno kao komponente klase bez predmeta klase, riskiraju pisanje komponenti koje djeluju lošije od komponenata klase.

Ovdje raspravljam o značajci useState-a koja je samo nakratko spomenuta u službenim FAQ-om o kukama. Detaljno razumijevanje ove značajke omogućit će vam da najbolje iskoristite React Hooks. Uz čitanje ove bilješke, pozivam vas da se poigrate sa Stress Testing React Hooks, alatom za usporedbu koji sam napisao da ilustriram ove osobine Kukova.

Opcije prije React Hooks

Pretpostavimo da imate skuplji izračun koji se mora dogoditi samo jednom prilikom postavljanja komponente, a pretpostavimo da taj izračun ovisi o nekoj podupiraču. Obična funkcionalna komponenta čini vrlo loš posao u ovome:

To je vrlo slabo, jer se skupi proračun izvodi na svakom renderu.

Komponente klase poboljšavaju na taj način omogućavajući nam da izvedemo određenu operaciju samo jednom, primjerice u konstruktoru:

Spremanjem rezultata izračuna u instancu, u ovom slučaju unutar lokalnog stanja komponente, možemo zaobići skupi izračun za svaki naredni prikaz. Možete vidjeti razliku koja to čini usporedbom klase i funkcionalne komponente s mojim alatom za usporedbu.

No, komponente klase imaju svoje nedostatke, kao što je spomenuto u službenim dokumentima React Hooks. Zbog toga su uvedene Kuke

Naivna implementacija uz useState

Kuka useState može se koristiti za proglašavanje "varijable stanja" i postavljanje na početnu vrijednost. Ta se vrijednost može mijenjati i pristupiti joj u narednim prikazima. Imajući to u vidu, naivno možete pokušati učiniti sljedeće da poboljšate performanse svoje funkcionalne komponente:

Možda mislite da, budući da se ovdje bavimo stanjem koje dijelimo između sljedećih prikazivanja, skupi proračun izvodi se samo na prvom renderu, baš kao i kod komponenata klase. Bili ste u krivu

Da biste vidjeli zašto, podsjetite se da je NaiveHooksComponent samo funkcija, funkcija koja se poziva na svaki prikaz. To znači da se useState poziva na svaki render. Kako funkcionira useState, komplicirana je priča koja nas ne mora zanimati. Važno je s čime se koristi useState: priziva se povratnom vrijednošću skupocjene. Ali mi ćemo znati kakva je ta povratna vrijednost samo ako se zaista pozivamo na skupu Izračun. Kao rezultat toga, naš NaiveHooksComponent osuđen je na izvršavanje skupog izračuna na svakom renderu, baš kao i prethodni FunctionalComponent koji nije koristio useState.

Do sada nam useState ne daje nikakve performanse, što se može potvrditi i mojim alatom za usporedbu. (Naravno, niz koji koristi UseState također sadrži funkciju koja nam omogućava lako ažuriranje varijable stanja, što je nešto što ne bismo mogli učiniti jednostavnom funkcionalnom komponentom.)

Tri načina za pamćenje skupih izračuna

Srećom, React Kuke pružaju nam tri mogućnosti za obradu stanja koje su podjednako uspješne kao i komponente klase.

1. koristiteMemo

Prva opcija je upotreba kuke useMemo:

U pravilu, useMemo skupi proračun ponovno izvodi samo ako se promijeni vrijednost arg. Ovo je samo pravilo, budući da buduće verzije Reacta mogu povremeno preračunati zapamćenu vrijednost.

Sljedeće dvije mogućnosti su pouzdanije.

2. Prijenos funkcija na useState

Druga je mogućnost proslijediti funkciju useState:

Ova se funkcija poziva samo na prvom prikazivanju. To je super korisno. (Iako morate zapamtiti da ako želite spremiti stvarnu funkciju u stanje, morate je prebaciti unutar druge funkcije. Inače na kraju spremate povratnu vrijednost funkcije umjesto same funkcije.)

3. useRef

Treća opcija je upotreba useRef kuke:

Ovaj je malo čudan, ali funkcionira i službeno se sankcionira. useRef vraća mutirajući ref objekt čiji trenutni ključ ukazuje na argument kojim se koristi UseRef. Ovaj ref objekt će ostati u narednim prikazima. Dakle, ako postavimo struju lijeno kao što to radimo gore, skupi proračun izvodi se samo jednom.

usporedba

Kao što možete vidjeti s mojim alatom za usporedbu, sve tri ove opcije jednako su uspješne kao i naša komponenta početnog razreda. Međutim, ponašanje upotrebe Memoa može se u budućnosti promijeniti. Dakle, ako želite imati jamstvo da se skupni izračun vrši samo jednom, trebali biste koristiti opciju 2, koja prolazi funkciju to useState, ili opciju 3, koja koristi useRef.

Izbor između ove dvije mogućnosti svodi se na to želite li ikada ažurirati rezultat skupog izračuna. Pomislite da je razlika između opcije 2 i opcije 3 analogna razlici između pohrane nečega u ovom.state ili pohranjivanja u ovo izravno.