Kuidas seda React Hooksi jõudluse lõksu vältida?

React Hooks lubab vältida klassikomponentide ülekulutamist, pakkudes samas samu eeliseid. Näiteks lubavad need meil kirjutada oleklikke funktsionaalseid komponente, ilma et peaksime muretsema klassi astme oleku talletamise pärast.

Riiklike komponentide kirjutamine Hooksuga nõuab siiski hoolt. On väike erinevus selle vahel, kuidas olek klassikomponendi konstruktoris initsialiseeritakse ja kuidas see UseState-i konksu abil initsialiseeritakse. Arendajad, kes juba mõistavad klassikomponente ja mõtlevad Hookidest lihtsalt kui klassikomponentidest, ilma et klassikogud oleksid, võivad kirjutada komponente, mis toimivad halvemini kui klassi komponendid.

Siinkohal arutan useState funktsiooni, mida on ametlikes konksude KKK-des vaid lühidalt mainitud. Selle funktsiooni üksikasjalik mõistmine võimaldab teil React Hookidest maksimaalselt kasu saada. Lisaks selle märkme lugemisele kutsun teid üles mängima stressitestiga React Hooks, mis on võrdlusinstrument, mille ma kirjutasin, et illustreerida neid konksude iseärasusi.

Reaktsioonide konksudele eelnevad valikud

Oletame, et teil on mõni kallis arvutus, mis peab komponendi seadistamisel toimuma vaid üks kord, ja oletame, et see arvutus sõltub mõnest tugiteenusest. Tavaline funktsionaalne komponent teeb selles valdkonnas väga halba tööd:

See toimib väga halvasti, kuna kallis arvutus tehakse iga krohvi korral.

Klassi komponendid paranevad sellega, võimaldades meil antud toimingut teostada ainult üks kord, näiteks konstruktoris:

Salvestades arvutuse tulemuse eksemplarile, antud juhul komponendi kohalikku olekusse, saame iga järgneva renderduse kallist arvutusest mööda minna. Selle erinevuse nägemiseks võrrelge klassikomponenti ja funktsionaalset komponenti minu mõõtevahendiga.

Kuid klassikomponentidel on oma puudused, nagu on mainitud ametlikes React Hooks dokumentides. Sellepärast hakati Hooke tutvustama.

Naiivne rakendamine koos useState'iga

Konksu useState saab kasutada olekumuutuja deklareerimiseks ja selle algväärtuse seadmiseks. Seda väärtust saab muuta ja sellele pääseda juurde järgnevates renderdustes. Seda silmas pidades võite oma funktsionaalse komponendi toimivuse parandamiseks naiivselt proovida teha järgmist:

Võite mõelda, et kuna siin on tegemist olekuga, mis on jagatud järgnevate renderduste vahel, tehakse kallis arvutus ainult esimesel renderdusel, nagu ka klassi komponentide puhul. Te oleksite eksinud.

Miks te peaksite seda mõistma, tuletage meelde, et NaiveHooksComponent on lihtsalt funktsioon, see funktsioon, millele kutsutakse iga renderdus. See tähendab, et useState kutsutakse igale renderdusele. Kuidas useState töötab, on keeruline lugu, mis ei pea meid puudutama. Oluline on see, millesse useState kutsutakse: Sellele kutsutakse välja kalkulatsiooni costCalculation tagastusväärtus. Kuid me teame ainult seda tagastatavat väärtust, kui tegelikult kutsume välja kallisarvestuse. Selle tulemusel on meie NaiveHooksComponent määratud tegema iga renderduse jaoks kalleid arvutusi, nagu ka meie eelmine funktsionaalne komponent, mis ei kasutanud useState'i.

Siiani ei anna useState meile mingeid jõudluse eeliseid, nagu saab kontrollida minu mõõdikutööriista abil. (Muidugi, massiiv, mille useState tagastab, sisaldab ka funktsiooni, mis võimaldab meil olekumuutujat hõlpsalt värskendada, mida me ei saaks lihtsa funktsionaalse komponendiga teha.)

Kolm viisi kallite arvutuste meeldejätmiseks

Õnneks pakub React Hooks meile kolme võimalust oleku käsitlemiseks, mis on sama tulemuslikud kui klassi komponendid.

1. useMemo

Esimene võimalus on kasutada konksu useMemo:

Rusikareeglina teostab useMemo kalli arvutuse alles siis, kui arg väärtus muutub. See on siiski ainult rusikareegel, kuna Reacti tulevased versioonid võivad aeg-ajalt meeldejäävat väärtust uuesti arvutada.

Kaks järgmist varianti on usaldusväärsemad.

2. Funktsioonide edastamine userState'ile

Teine võimalus on funktsiooni useState edastamine:

See funktsioon käivitatakse ainult esimesel renderdamisel. See on ülimalt kasulik. (Ehkki peate meeles pidama, et kui soovite tegelikku funktsiooni olekusse salvestada, peate selle mässima teise funktsiooni sisse. Vastasel korral salvestate funktsiooni tagastamise väärtuse, mitte funktsiooni enda.)

3. useRef

Kolmas võimalus on kasutada konksu useRef:

See on natuke imelik, kuid töötab ja on ametlikult sanktsioneeritud. useRef tagastab muudetava viiteobjekti, mille praegune võti osutab argumendile, millele useRef kutsutakse. See viiteobjekt püsib ka järgmistes renderdustes. Nii et kui seada voolutugevus lahedalt nagu ülalpool, tehakse kallis arvutus ainult üks kord.

Võrdlus

Nagu näete minu võrdlusinstrumendi puhul, on kõik need kolm võimalust sama tulemuslikud kui meie algne klassi komponent. UseMemo käitumine võib tulevikus siiski muutuda. Nii et kui soovite garantiid, et kallis arvutus tehakse ainult üks kord, peaksite kasutama 2. võimalust, mis annab funktsiooni useState üle, või 3. võimalust, mis kasutab UseRef.

Nende kahe valiku vahel langeb küsimus, kas soovite kunagi kalli arvutuse tulemust värskendada. Mõelge variandi 2 ja 3 erinevusele, mis on analoogne erinevusega selles olekus või otse selles salvestamise vahel.