Noțiuni introductive cu API-ul React Hooks
Publicat: 2022-03-10Când React 16.8 a fost lansat oficial la începutul lunii februarie 2019, a fost livrat cu un API suplimentar care vă permite să utilizați starea și alte funcții în React fără a scrie o clasă. Acest API suplimentar se numește Hooks și devin populare în ecosistemul React, de la proiecte open-source până la utilizarea în aplicații de producție.
React Hooks sunt complet înscrise, ceea ce înseamnă că rescrierea codului existent nu este necesară, nu conțin modificări nerespective și sunt disponibile pentru utilizare odată cu lansarea React 16.8. Unii dezvoltatori curioși au folosit API-ul Hooks chiar înainte de a fi lansat oficial, dar pe atunci nu era stabil și era doar o caracteristică experimentală. Acum este stabil și recomandat dezvoltatorilor React să îl folosească.
Notă : nu vom vorbi despre React sau JavaScript în general. O bună cunoaștere a ReactJS și JavaScript vă va fi utilă pe măsură ce lucrați prin acest tutorial.
Ce sunt React Hooks?
React Hooks sunt funcții încorporate care permit dezvoltatorilor React să utilizeze metode de stare și ciclu de viață în componentele funcționale, de asemenea, lucrează împreună cu codul existent, astfel încât să poată fi adoptate cu ușurință într-o bază de cod. Modul în care Hook-urile au fost prezentate publicului a fost că le permit dezvoltatorilor să folosească starea în componente funcționale, dar sub capotă, Hook-urile sunt mult mai puternice decât atât. Acestea permit dezvoltatorilor React să se bucure de următoarele beneficii:
- Reutilizarea codului îmbunătățită;
- Compoziție mai bună a codului;
- Valori implicite mai bune;
- Partajarea logicii non-vizuale cu ajutorul cârligelor personalizate;
- Flexibilitate în deplasarea în sus și în jos în arborele
components
.
Cu React Hooks, dezvoltatorii au puterea de a folosi componente funcționale pentru aproape tot ceea ce trebuie să facă, de la doar redarea interfeței de utilizare până la gestionarea stării și, de asemenea, a logicii - ceea ce este destul de frumos.
Motivația din spatele lansării React Hooks
Conform documentației oficiale ReactJS, următoarele sunt motivația din spatele lansării React Hooks:
- Reutilizarea logicii stateful între componente este dificilă.
Cu Hooks, puteți reutiliza logica între componente fără a le schimba arhitectura sau structura. - Componentele complexe pot fi dificil de înțeles.
Când componentele devin mai mari și efectuează multe operațiuni, devine greu de înțeles pe termen lung. Cârligele rezolvă acest lucru permițându-vă să separați o anumită componentă în diferite funcții mai mici, în funcție de ce părți din această componentă separată sunt legate (cum ar fi configurarea unui abonament sau preluarea datelor), mai degrabă decât să forțați o divizare pe baza metodelor ciclului de viață. - Clasele sunt destul de confuze.
Clasele reprezintă o piedică în învățarea Reacționează în mod corespunzător; ar trebui să înțelegeți cum funcționeazăthis
în JavaScript, care diferă de alte limbi. React Hooks rezolvă această problemă permițând dezvoltatorilor să folosească cele mai bune funcții React fără a fi nevoie să folosească clase.
Regulile cârligelor
Există două reguli principale care trebuie respectate cu strictețe, așa cum este menționat de echipa de bază React, în care au fost subliniate în documentația propunerii de hooks.
- Asigurați-vă că nu utilizați Hook-uri în bucle, condiții sau funcții imbricate;
- Utilizați numai cârlige din interiorul React Functions.
Cârlige React de bază
Există 10 cârlige încorporate care au fost livrate cu React 16.8, dar cârligele de bază (utilizate în mod obișnuit) includ:
-
useState()
-
useEffect()
-
useContext()
-
useReducer()
Acestea sunt cele 4 cârlige de bază care sunt utilizate în mod obișnuit de dezvoltatorii React care au adoptat cârlige React în bazele lor de cod.
useState()
useState()
permite dezvoltatorilor React să actualizeze, să gestioneze și să manipuleze starea din interiorul componentelor funcționale fără a fi nevoie să o convertească într-o componentă de clasă. Să folosim fragmentul de cod de mai jos este o componentă simplă a contorului de vârstă și o vom folosi pentru a explica puterea și sintaxa cârligului useState()
.
function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }
Dacă ați observat, componenta noastră pare destul de simplă, concisă și acum este o componentă funcțională și, de asemenea, nu are nivelul de complexitate pe care l-ar avea o componentă de clasă.
Hook-ul useState()
primește o stare inițială ca argument și apoi returnează, utilizând destructurarea matricei în JavaScript, cele două variabile din matrice pot fi numite ce. Prima variabilă este starea actuală, în timp ce a doua variabilă este o funcție care este menită să actualizeze starea prin furnizarea unei noi stări.
Acesta este modul în care ar trebui să arate componenta noastră când este redată în aplicația noastră React. Făcând clic pe butonul „Măriți vârsta mea”, starea vârstei se va schimba și componenta va funcționa la fel ca o componentă de clasă cu stare.
useEffect()
useEffect()
acceptă o funcție care ar conține cod efectiv. În componentele funcționale, efecte precum mutațiile, abonamentele, temporizatoarele, înregistrarea în jurnal și alte efecte nu pot fi plasate într-o componentă funcțională, deoarece acest lucru ar duce la o mulțime de inconsecvențe atunci când interfața de utilizare este redată și, de asemenea, erori confuze.
În utilizarea cârligului useEffect()
, funcția eficientă transmisă în acesta se va executa imediat după ce randarea a fost afișată pe ecran. Efectele sunt în principiu privite în modul imperativ de a construi interfețe de utilizare, care este destul de diferit de modul funcțional al lui React.
În mod implicit, efectele sunt executate în principal după ce randarea a fost finalizată, dar aveți opțiunea de a le declanșa și atunci când anumite valori se modifică.
useEffect()
este utilizat mai ales pentru efectele secundare care sunt de obicei folosite pentru interacțiunile cu API-ul Browser/DOM sau preluarea de date sau abonamentele externe, asemănătoare API-ului. De asemenea, dacă sunteți deja familiarizat cu modul în care funcționează metodele ciclului de viață React, vă puteți gândi și la useEffect()
hook ca la montarea , actualizarea și demontarea componentelor - toate combinate într-o singură funcție. Ne permite să replicăm metodele ciclului de viață în componente funcționale.
Vom folosi fragmentele de cod de mai jos pentru a explica cel mai simplu mod pe care îl putem folosi folosind cârligul useEffect()
.
Pasul 1: Definiți starea aplicației dvs
import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
La fel cum am discutat în secțiunea anterioară despre cum să folosim cârligul useState()
pentru a gestiona starea din componentele funcționale, l-am folosit în fragmentul nostru de cod pentru a seta starea aplicației noastre care redă numele meu complet.
Pasul 2: Apelați Hook useEffect
import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({FirstName: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
Am importat acum cârligul useEffect
și am folosit, de asemenea, funcția useEffect()
pentru a seta starea proprietății noastre de nume și prenume, care este destul de ordonată și concisă.
Este posibil să fi observat cârligul useEffect
în al doilea argument care este o matrice goală; acest lucru se datorează faptului că conține un apel către setFullName
care nu are o listă de dependențe. Trecerea celui de-al doilea argument va împiedica un lanț infinit de actualizări ( componentDidUpdate()
) și va permite, de asemenea, cârligului nostru useEffect()
să acționeze ca o metodă ciclului de viață componentDidMount
și să randeze o singură dată, fără re-rendarea la fiecare modificare a arborelui.
Aplicația noastră React ar trebui să arate acum astfel:
De asemenea, putem folosi modificarea proprietății de title
a aplicației noastre în cadrul useEffect()
apelând funcția setTitle()
, așa:
import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({firstName: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
Acum, după ce aplicația noastră a fost redată din nou, acum arată noul titlu.
useContext()
useContext()
acceptă un obiect context, adică valoarea returnată de la React.createContext
și apoi returnează valoarea contextului curent pentru acel context.
Acest cârlig oferă componentelor funcționale acces ușor la contextul aplicației React. Înainte de introducerea cârligului useContext
, ar trebui să configurați un contextType
sau un <Consumer>
pentru a vă accesa starea globală transmisă de la un furnizor într-o componentă de clasă.
Practic, cârligul useContext
funcționează cu API-ul React Context, care este o modalitate de a partaja date profund în aplicația dvs., fără a fi nevoie să treceți manual elementele de recuzită ale aplicației la diferite niveluri. Acum, useContext()
face utilizarea contextului puțin mai ușoară.
Fragmentele de cod de mai jos vor arăta cum funcționează API-ul Context și cum îl îmbunătățește useContext
Hook.
Modul normal de utilizare a API-ului de context
import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));
Acum să defalcăm fragmentul de cod și să explicăm fiecare concept.
Mai jos, creăm un context numit NumberContext
. Este menit să returneze un obiect cu două valori: { Provider, Consumer }
.
const NumberContext = React.createContext();
Apoi folosim valoarea Provider
care a fost returnată din NumberContext
pe care l-am creat pentru a face o anumită valoare disponibilă tuturor copiilor.
function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }
Cu aceasta, putem folosi valoarea Consumer
care a fost returnată din NumberContext
pe care l-am creat pentru a obține valoarea pe care am pus-o la dispoziție tuturor copiilor. Dacă ați observat, această componentă nu a primit nicio recuzită.
function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));
Observați modul în care am reușit să obținem valoarea din componenta App
în componenta Display
prin împachetarea conținutului nostru într-un NumberContext.Consumer
și folosind metoda de randare props pentru a prelua valoarea și a o reda.
Totul funcționează bine, iar metoda de recuzită de randare pe care am folosit-o este un model foarte bun pentru gestionarea datelor dinamice, dar, pe termen lung, introduce unele imbricare inutile și confuzie dacă nu sunteți obișnuit cu asta.
Folosind metoda useContext
Pentru a explica metoda useContext
vom rescrie componenta Display
folosind cârligul useContext.
// import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }
Asta este tot ce trebuie să facem pentru a ne arăta valoarea. Destul de îngrijit, nu? Apelați cârligul useContext()
și treceți în contextul pe care l-am creat și luăm valoarea din acesta.
Notă: Nu uitați că argumentul care este transmis cârligului useContext trebuie să fie obiectul context în sine și orice componentă care apelează useContext va fi întotdeauna redată când valoarea contextului se schimbă.
useReducer()
Cârligul useReducer
este utilizat pentru gestionarea stărilor complexe și a tranzițiilor în stare. Preia o funcție de reducer
și, de asemenea, o intrare de stare inițială; apoi, returnează starea curentă și, de asemenea, o funcție de dispatch
ca ieșire prin intermediul destructurarii matricei.
Codul de mai jos este sintaxa adecvată pentru utilizarea cârligului useReducer
.
const [state, dispatch] = useReducer(reducer, initialArg, init);
Este un fel de alternativă la cârligul useState
; de obicei, este de preferat să useState
atunci când aveți o logică complexă a stării care are de-a face cu mai multe sub-valori sau când următoarea stare este dependentă de cea anterioară.
Alte cârlige React disponibile
useCallback | Acest cârlig returnează o funcție de apel invers care este memorată și care se schimbă numai dacă se modifică o dependență din arborele de dependență. |
useMemo | Acest cârlig returnează o valoare memorată, puteți trece o funcție de „creare” și, de asemenea, o serie de dependențe. Valoarea pe care o returnează va folosi din nou valoarea memorată numai dacă se modifică una dintre dependențele din arborele de dependență. |
useRef | Acest cârlig returnează un obiect ref mutabil a cărui proprietate .current este inițializată la argumentul transmis ( initialValue ). Obiectul returnat va fi disponibil pe toată durata de viață a componentei. |
useImperativeHandle | Acest cârlig este folosit pentru personalizarea valorii instanței care este disponibilă pentru componentele părinte atunci când se utilizează refs în React. |
useLayoutEffect | Acest cârlig similar cu cârligul useEffect , cu toate acestea, se declanșează sincron după toate mutațiile DOM. De asemenea, se redă în același mod ca componentDidUpdate și componentDidMount . |
useDebugValue | Acest cârlig poate fi folosit pentru a afișa o etichetă pentru cârlige personalizate în React Dev Tools. Este foarte util pentru depanare cu React Dev Tools. |
Cârlige personalizate React
Un „Hook personalizat” este o funcție JavaScript ale cărei nume sunt prefixate cu cuvântul use
și poate fi folosită pentru a apela alte Hook. De asemenea, vă permite să extrageți logica componentelor în funcții reutilizabile; sunt funcții JavaScript obișnuite care pot folosi alte Hook-uri în interiorul acestuia și, de asemenea, conțin o logică cu stare comună care poate fi utilizată în mai multe componente.
Fragmentele de cod de mai jos demonstrează un exemplu de React Hook personalizat pentru implementarea derulării infinite (de Paulo Levy):
import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };
Acest Hook personalizat acceptă două argumente care sunt start
și pace
. Argumentul de pornire este numărul inițial de elemente care trebuie redate, în timp ce argumentul de ritm este numărul următor de elemente care urmează să fie redate. În mod implicit, argumentele de start
și de pace
sunt setate la 30
și, respectiv, 10
, ceea ce înseamnă că puteți apela Hook fără niciun argument și acele valori implicite vor fi folosite în schimb.
Deci, pentru a folosi acest Hook într-o aplicație React, l-am folosi cu un API online care returnează date „false”:
import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;
Codul de mai sus va afișa o listă de date false ( userID
și title
) care folosesc cârligul de defilare infinit pentru a afișa numărul inițial de date pe ecran.
Concluzie
Sper că v-a plăcut să lucrați prin acest tutorial. Puteți citi oricând mai multe despre React Hooks din referințele de mai jos.
Dacă aveți întrebări, le puteți lăsa în secțiunea de comentarii și voi răspunde cu plăcere la fiecare!
Repo de sprijin pentru acest articol este disponibil pe Github.
Resurse și lecturi suplimentare
- „Hooks API Reference”, React.js Docs
- „Ce sunt React Hooks?”, Robin Wieruch
- „Cum funcționează
useContext
Hook”, Dave Ceddia - „React Hooks: Cum se utilizează
useEffect()
”, Hossein Ahmadi, mediu - „Scrieți-vă propriile cârlige personalizate de reacție”, Aayush Jaiswal, Medium
- „Rețete React Hook ușor de înțeles”, Gabe Ragland, useHooks()