Învățați cum să îmblânziți utilizarea lui React Callback Hook

Publicat: 2022-04-27

Nu este un secret pentru nimeni că React.js a devenit foarte popular în ultimii ani. Acum este biblioteca JavaScript aleasă de mulți dintre cei mai importanți jucători de pe internet, inclusiv Facebook și WhatsApp.

Unul dintre principalele motive pentru creșterea sa a fost introducerea cârligelor în versiunea 16.8. Cârligele React vă permit să accesați funcționalitatea React fără a scrie componente ale clasei. Acum componentele funcționale cu cârlige au devenit structura de bază a dezvoltatorilor pentru lucrul cu React.

În această postare pe blog, vom săpa mai adânc într-un cârlig specific - useCallback - deoarece atinge o parte fundamentală a programării funcționale cunoscută sub numele de memorare. Veți ști exact cum și când să utilizați cârligul useCallback și să profitați la maximum de capabilitățile sale de îmbunătățire a performanței.

Gata? Să ne scufundăm!


Ce este memorarea?

Memorizarea este atunci când o funcție complexă își stochează ieșirea, astfel încât data viitoare este apelată cu aceeași intrare. Este similar cu stocarea în cache, dar la un nivel mai local. Poate sări peste orice calcule complexe și poate returna rezultatul mai rapid, deoarece este deja calculat.

Acest lucru poate avea un efect semnificativ asupra alocării și performanței memoriei, iar această solicitare este ceea ce este menit să atenueze cârligul useCallback .

Utilizarea lui ReactCallback vs useMemo

În acest moment, merită menționat că useCallback se împerechează frumos cu un alt cârlig numit useMemo . Le vom discuta pe amândouă, dar în această piesă ne vom concentra pe useCallback ca subiect principal.

Diferența cheie este că useMemo returnează o valoare memorată, în timp ce useCallback returnează o funcție memorată. Aceasta înseamnă că useMemo este folosit pentru stocarea unei valori calculate, în timp ce useCallback returnează o funcție pe care o puteți apela mai târziu.

Aceste cârlige vă vor returna o versiune în cache, cu excepția cazului în care una dintre dependențele lor (de exemplu, starea sau elementele de recuzită) se schimbă.

Să aruncăm o privire la cele două funcții în acțiune:

 import { useMemo, useCallback } from 'react' const values = [3, 9, 6, 4, 2, 1] // This will always return the same value, a sorted array. Once the values array changes then this will recompute. const memoizedValue = useMemo(() => values.sort(), [values]) // This will give me back a function that can be called later on. It will always return the same result unless the values array is modified. const memoizedFunction = useCallback(() => values.sort(), [values])

Fragmentul de cod de mai sus este un exemplu artificial, dar arată diferența dintre cele două apeluri inverse:

  1. memoizedValue va deveni matricea [1, 2, 3, 4, 6, 9] . Atâta timp cât variabila values ​​rămâne, la fel va rămâne memoizedValue și nu se va recalcula niciodată.
  2. memoizedFunction va fi o funcție care va returna matricea [1, 2, 3, 4, 6, 9] .

Ceea ce este grozav la aceste două apeluri inverse este că devin stocate în cache și rămân până când se modifică matricea de dependențe. Aceasta înseamnă că, la randare, nu vor primi gunoiul colectat.

React.js este acum biblioteca JavaScript aleasă pentru mulți dintre cei mai mari jucători de pe internet, inclusiv Facebook și WhatsApp. Aflați mai multe în acest ghid ️ Faceți clic pentru a trimite un Tweet

Redare și reacție

De ce este importantă memorarea când vine vorba de React?

Are de-a face cu modul în care React vă redă componentele. React folosește un Virtual DOM stocat în memorie pentru a compara datele și a decide ce să actualizeze.

DOM-ul virtual ajută React cu performanță și menține rapid aplicația. În mod implicit, dacă orice valoare din componenta dvs. se modifică, întreaga componentă va fi redată din nou. Acest lucru face ca React să fie „reactiv” la intrarea utilizatorului și permite ecranului să se actualizeze fără a reîncărca pagina.

Nu doriți să vă redați componenta deoarece modificările nu vor afecta acea componentă. Aici este utilă memorarea prin useCallback și useMemo .

Când React redă din nou componenta dvs., acesta recreează și funcțiile pe care le-ați declarat în interiorul componentei dvs.

Rețineți că atunci când comparați egalitatea unei funcții cu o altă funcție, acestea vor fi întotdeauna false. Deoarece o funcție este și un obiect, se va egala doar cu ea însăși:

 // these variables contain the exact same function but they are not equal const hello = () => console.log('Hello Matt') const hello2 = () => console.log('Hello Matt') hello === hello2 // false hello === hello // true

Cu alte cuvinte, atunci când React redă din nou componenta dvs., va vedea toate funcțiile care sunt declarate în componenta dvs. ca fiind funcții noi.

Acest lucru este bine de cele mai multe ori, iar funcțiile simple sunt ușor de calculat și nu vor afecta performanța. Dar celelalte ori când nu doriți ca funcția să fie văzută ca o funcție nouă, vă puteți baza pe useCallback pentru a vă ajuta.

S-ar putea să vă gândiți: „Când nu aș vrea ca o funcție să fie văzută ca o funcție nouă?” Ei bine, există anumite cazuri când useCallback are mai mult sens:

  1. Transmiteți funcția unei alte componente care este, de asemenea, memorată ( useMemo )
  2. Funcția dumneavoastră are o stare internă pe care trebuie să o rețină
  3. Funcția dvs. este o dependență de un alt cârlig, cum ar fi useEffect , de exemplu

Beneficiile de performanță ale React useCallback

Când useCallback este utilizat în mod corespunzător, poate ajuta la accelerarea aplicației și la prevenirea re-rendarii componentelor dacă nu este nevoie.

Să presupunem, de exemplu, că aveți o componentă care preia o cantitate mare de date și este responsabilă pentru afișarea acestor date sub forma unei diagrame sau a unui grafic, astfel:

Un grafic cu bare colorat care compară timpul total al tranzacției PHP, MySQL, Reddis și extern (altele) în milisecunde.
Grafic cu bare generat folosind o componentă React.

Să presupunem că componenta părinte pentru re-rendările componentei de vizualizare a datelor, dar elementele de recuzită sau starea modificate nu afectează acea componentă. În acest caz, probabil că nu doriți sau nu trebuie să îl redați din nou și să recărcați toate datele. Evitarea acestei re-rendare și refacere poate economisi lățimea de bandă a utilizatorului și poate oferi o experiență mai fluidă pentru utilizator.

Te lupți cu timpii de nefuncționare și problemele WordPress? Kinsta este soluția de găzduire concepută pentru a vă economisi timp! Verificați caracteristicile noastre

Dezavantajele utilizării React Callback

Deși acest cârlig vă poate ajuta să îmbunătățiți performanța, vine și cu capcanele sale. Câteva lucruri de luat în considerare înainte de a utiliza useCallback (și useMemo ) sunt:

  • Colectarea gunoiului: celelalte funcții care nu sunt deja memorate vor fi aruncate de React pentru a elibera memorie.
  • Alocarea memoriei: similar cu colectarea gunoiului, cu cât aveți mai multe funcții memorate, cu atât mai multă memorie va fi necesară. În plus, de fiecare dată când utilizați aceste apeluri inverse, există o grămadă de cod în interiorul React care trebuie să folosească și mai multă memorie pentru a vă oferi rezultatul stocat în cache.
  • Complexitatea codului: Când începeți să încadrați funcții în aceste cârlige, creșteți imediat complexitatea codului. Acum necesită mai multă înțelegere a motivului pentru care aceste cârlige sunt utilizate și confirmarea că sunt utilizate corect.

Să fii conștient de capcanele de mai sus te poate scuti de durerea de cap de a te împiedica singur de ele. Când vă gândiți să useCallback , asigurați-vă că beneficiile de performanță vor depăși dezavantajele.

Reacționează folosind Exemplu de apel invers

Mai jos este o configurare simplă cu o componentă Button și o componentă Counter. Contorul are două părți de stare și redă două componente Button, fiecare care va actualiza o parte separată a stării componentelor Contor.

Componenta Button are două elemente de recuzită: handleClick și name. De fiecare dată când butonul este randat, acesta se va conecta la consolă.

 import { useCallback, useState } from 'react' const Button = ({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> } const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) return ( <> {countOne} {countTwo} <Button handleClick={() => setCountOne(countOne + 1)} name="button1" /> <Button handleClick={() => setCountTwo(countTwo + 1)} name="button1" /> </> ) }

În acest exemplu, de fiecare dată când faceți clic pe oricare dintre butoane, veți vedea acest lucru în consolă:

 // counter rendered // button1 rendered // button2 rendered

Acum, dacă aplicăm useCallback funcțiilor noastre handleClick și înfășurăm Butonul în React.memo , putem vedea ce ne oferă useCallback . React.memo este similar cu useMemo și ne permite să memorăm o componentă.

 import { useCallback, useState } from 'react' const Button = React.memo(({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> }) const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) const memoizedSetCountOne = useCallback(() => setCountOne(countOne + 1), [countOne) const memoizedSetCountTwo = useCallback(() => setCountTwo(countTwo + 1), [countTwo]) return ( <> {countOne} {countTwo} <Button handleClick={memoizedSetCountOne} name="button1" /> <Button handleClick={memoizedSetCountTwo} name="button1" /> </> ) }

Acum, când facem clic pe oricare dintre butoane, vom vedea doar butonul pe care l-am făcut clic pentru a vă conecta în consolă:

 // counter rendered // button1 rendered // counter rendered // button2 rendered

Am aplicat memorarea componentei noastre de buton, iar valorile prop care îi sunt transmise sunt văzute ca fiind egale. Cele două funcții handleClick sunt stocate în cache și vor fi văzute ca aceeași funcție de către React până când valoarea unui element din matricea de dependențe se schimbă (de exemplu, countOne , countTwo ).

Sunteți gata să aflați exact cum și când să utilizați cârligul useCallback, precum și cum să profitați la maximum de capabilitățile sale de îmbunătățire a performanței? Începeți aici! Faceți clic pentru a trimite pe Tweet

rezumat

Oricât de cool sunt useCallback și useMemo , amintiți-vă că au cazuri de utilizare specifice - nu ar trebui să includeți fiecare funcție cu aceste cârlige. Dacă funcția este complexă din punct de vedere computațional, o dependență de un alt cârlig sau un suport transmis unei componente memorate sunt indicatori buni pe care ați putea dori să îi ajungeți pentru useCallback .

Sperăm că acest articol te-a ajutat să înțelegi această funcționalitate avansată React și te-a ajutat să câștigi mai multă încredere în programarea funcțională pe parcurs!