I løpet av mange intervjuer har jeg lagt merke til at selv erfarne programmerere har problemer med å skille mellom Hooks, for ikke å snakke om de mer avanserte funksjonene. Derfor vil jeg i denne artikkelen prøve å forklare hvordan Hooks bør brukes.
Det viktigste du trenger å huske om Hooks:
de kan bare brukes i funksjonskomponenter - klassekomponenter har egen livssyklusimplementering;
de begynner alltid med bruk;
kan du bruke så mange Hooks du vil, men du må huske at bruken av dem har innvirkning på den generelle ytelsen;
de må utføres i samme rekkefølge ved hver rendering ... men hvorfor? La oss ta en titt på et eksempel:
<code>srcFunctionComponent.js
Linje 11:5: React Kroken "useEffect" kalles betinget. <strong>React Kroker</strong> må kalles i nøyaktig samme rekkefølge i hver komponent render .eslintreact-hooks/rules-of-hooks
Som du kan se, er det bare en eslint-advarsel, så du kan deaktivere den ved å legge til en kommando nedenfra øverst i Funksjonskomponent
/* eslint-deaktiver react-hooks/rules-of-hooks */
og det vil fungere, men bare til vi oppfyller betingelsen som kjører kroken vår. Det neste vi vil se er denne feilen.
Uoppdaget feil: Gjenga flere kroker enn under forrige gjengivelse.
React 5
FunctionComponent FunctionComponent.js:11
React 12
unstable_runWithPriority scheduler.development.js:468
React 17
js index.js:7
js main.chunk.js:905
Webpack 7
react-dom.development.js:15162
Hvorfor skjer dette? React er avhengig av rekkefølgen som Hooks kalles i. React vet ikke hva som skal returneres for useEffect fordi det ikke finnes noen slik Hook i linjen som kan sjekkes.
Husk at eslint er et kraftig verktøy som hjelper oss med å fange opp mange potensielle feil. Det er farlig å deaktivere advarslene, så sjekk alltid om det å ignorere advarselen kan føre til at appen krasjer.
useState
Du vet sikkert hvordan det ser ut 😉.
const [value, setValue] = useState(0);
Så du har fire elementer: tilstand (reaktiv verdi), oppdateringsfunksjon (setter), faktisk krok (funksjon) og valgfri startverdi. Hvorfor returnerer den en matrise? Fordi vi kan restrukturere den som vi vil.
Nå vil jeg fokusere på det siste elementet - startverdien. Det er to måter å overføre den opprinnelige tilstanden på:
Ved hardkodet verdi eller lignende - som vil bli kalt ved hver rendering
const [value, setValue] = useState(0);
Av en funksjonsversjon. Det er veldig nyttig hvis vi ønsker å kjøre den opprinnelige tilstanden bare én gang, på den aller første gjengivelsen. Kanskje du trenger å gjøre mange komplekse beregninger for å motta den opprinnelige tilstanden? Det vil pent redusere ressurskostnadene, yay!
En annen ting som kan skape feil i appflyten: Du vet sikkert hvordan du oppdaterer en tilstand, ikke sant?
setValue(1);
Ja, men hva om jeg vil oppdatere statusen basert på en tidligere status?
setValue(verdi + 1);
Ja... Men nei... Hva om du prøver å kalle setter-funksjonen to ganger, den ene etter den andre? Den anbefalte måten å oppdatere en tilstand basert på den forrige tilstanden på, er å bruke en funksjon. Det garanterer at du refererer til den forrige tilstanden
Denne kroken tar to argumenter (det andre er valgfritt), og vi bruker den til å håndtere sideeffekter. Avhengig av hva vi sender som det andre argumentet, vil kroken bli kalt på forskjellige måter:
uten andre argument - hver gjengivelse
useEffect(() => {
doSomething();
});
tom matrise - bare ved første gjengivelse
useEffect(() => {
doSomething();
}, []);
med avhengigheter - hver gang verdien i avhengighetsarrayen endres
Med useEffect kan vi bruke noe som kalles cleanup. Hva er den til? Det er veldig nyttig, men jeg tror det er best for å rydde opp i hendelseslyttere. La oss si at du vil opprette en hendelseslytter som avhenger av en tilstand. Du ønsker ikke å legge til en ny hendelseslytter ved hver tilstandsendring, for etter noen få renderinger vil det være så mange lyttere at det vil påvirke appens ytelse. En god måte å unngå slike ting på er å bruke opprydningsfunksjonen. Hvordan gjør man det? Bare legg til en returfunksjon til useEffect.
Fordi det er inne i useEffect Hook, kalles returen avhengig av avhengighetsarrayen - på hver gjengivelse, bare på den første gjengivelsen, eller når verdien i avhengighetsarrayen endres. Men når komponenten avmonteres, vil cleaning uansett bli kalt på det andre argumentet. Returen kode kalles før den faktiske koden fra Hook. Det er veldig logisk - først renser du den gamle, og deretter oppretter du en ny. Ikke sant?
Til å begynne med ser det ok ut. Du henter noen data, og når dataene kommer, oppdaterer du tilstanden. Og her er fellen:
Noen ganger vil du motta en slik advarsel: Kan ikke utføre en React-tilstandsoppdatering på en umontert komponent. Dette er en no-op, men det indikerer en minnelekkasje i applikasjonen din. Du løser problemet ved å avbryte alle abonnementer og asynkrone oppgaver i en useEffect-oppryddingsfunksjon.
Årsaken er at komponenten kan avmonteres i mellomtiden, men appen vil fortsatt prøve å oppdatere tilstanden til komponenten etter at løftet er oppfylt. Hvordan håndterer man dette? Du må sjekke om komponenten eksisterer.
Merk: Det finnes en veldig lik krok => useLayoutEffect() - tilbakekallingen kjøres etter at komponenten er gjengitt, men før domen oppdateres visuelt. Det er nyttig når du arbeider med getBoundingClientRect(), men du bør bruke useEffect som standard. Hvorfor det? Fordi det kan blokkere visuelle oppdateringer - når du har en kompleks kode inne i effekten Hook.
useContext
Hva kan man bruke det til? Deling av data uten å sende props. Består av følgende elementer:
I child må du importere konteksten og kalle useContext-kroken og sende konteksten som et argument.
import { UserContext } fra "./App";
const { name } = useContext(UserContext);
return <h1>Hei {navn}<>
```
Voilà. Ser kult ut. Mest for overføring av globale data som temaer osv. Anbefales ikke for bruk i oppgaver med svært dynamiske endringer.
Vi kan selvfølgelig opprette en egendefinert kontekstleverandør og en egendefinert krok for å redusere boilerplate i stedet ... men jeg vil ta for meg egendefinerte kroker i neste artikkel.
useReducer
Det lar oss administrere tilstanden og gjengi på nytt når tilstanden endres - som useState. Den ligner på redux reducer. Denne er bedre enn useState når tilstandslogikken er mer komplisert.
Når skal man bruke det? Når vi ønsker å oppnå referanselikhet (og dermed redusere antallet opprettede funksjoner). Denne kroken returnerer funksjonen, i motsetning til useMemo som returnerer verdien.
Eksempel: Opprett en funksjon i den overordnede komponenten, og send den deretter via props
Sjekk deretter i underordnet komponent hvor mange ganger effekten Hook vil bli kalt etter at funksjonen er lagt til i avhengighetsarrayen:
// Barn
useEffect(() => {
console.log("getSquaredValue", getSquaredValue());
}, [getSquaredValue]);
Den vil logge til konsollen ved hver gjengivelse! Selv om verdiene inne i getSquaredValue() funksjonen ble ikke endret. Men vi kan unngå dette ved å pakke inn funksjonen i useCallback
Det er ikke nøytralt når man ser på ressurskostnadene - useMemo må kalles ved hver gjengivelse, lagrer verdien i minnet og sammenligner (minneoverhead),
bruker Memoization - optimaliseringsteknikken, en spesifikk form for hurtigbufring.
Du bør bare bruke den i to scenarier:
Hvis du vil unngå å kalle en kompleks kode ved hver gjengivelse;
Hvis du ønsker å oppnå referansemessig likhet.
La oss se litt nærmere på det andre tilfellet. Vi ønsker å bruke useEffect med et objekt som en avhengighet. Fordi objekter sammenlignes ved hjelp av referansen, vil useEffect bli kalt ved hver rendering. For å unngå slike ting kan vi kombinere useEffect med useMemo for å memotisere slike objekter og deretter sende de memotiserte objektene til avhengighetsarrayen. Kort eksempel:
Hobbit-objektet gjør at avhengigheten til useEffect-kroken (linje 49) endres ved hver rendering. Flytt den inn i useEffect-tilbakekallet. Alternativt kan du pakke inn initialiseringen av 'hobbit' i sin egen useMemo ()-krok.eslintreact-hooks/exhaustive-deps
Det viktigste: useRef utløser ikke ny gjengivelse (som useState) fordi den ikke er koblet til gjengivelsessyklusen - den beholder den samme referansen mellom gjengivelser.
const ref = useRef(0);
For å hente den lagrede verdien må du bruke en aktuell egenskap (ref er et objekt) - -. ref.strøm
Det andre tilfellet vi kan bruke denne kroken til, er å referere til elementer i HTML. Hvert element har et ref-attributt. Så vi kan håndtere fokus, hendelser osv.
Det tredje tilfellet er at vi kan bruke refs til å håndtere ukontrollerte komponenter. Du kan lese mer om dem i react-dokumenter, men kort fortalt ser det slik ut:
Som du ser, er det ingen hendelsesbehandler, den husker bare den inntastede verdien. Den er perfekt for å håndtere enkle skjemaer når du bare vil lese lagrede verdier når du trenger dem (for eksempel når du sender inn).
Bonus: Det er flott når du trenger å huske tidligere tilstandsverdier. Du kan bruke useEffect Hook, bare send tilstanden til ref.
Som du ser, er Hooks ikke så opplagte. Vi kan kombinere dem for å løse mange problemer. Du vil helt sikkert ha stor nytte av å studere dette emnet.
Og det finnes også tilpassede kroker...
For å oppsummere, React kroker har revolusjonert måten React-utviklere tilnærming bygning webapplikasjoner . Ved å tilby en mer intuitiv og effektiv måte å administrere tilstand og livssyklus i funksjonelle komponenter på, har hooks blitt en integrert del av React-utvikling .
Enten du er en erfaren utvikler eller nettopp har begynt med React, er det avgjørende å forstå de mest populære krokene og deres bruksområder. Med kroker som useState, useEffect, useContext og flere, React-komponenter kan bygges med renere og mer gjenbrukbar kode. I tillegg gir muligheten til å lage tilpassede kroker gjør det mulig for utviklere å kapsle inn og dele logikk på tvers av flere komponenter, noe som fremmer gjenbruk av kode og modularitet. Etter hvert som React fortsetter å utvikle seg og introdusere nye funksjoner, vil hooks utvilsomt spille en sentral rolle når det gjelder å utnytte det fulle potensialet i rammeverket.
Så uansett om du jobber med en liten funksjonsapp eller en storstilt webapplikasjon, er det viktig å omfavne React kroker vil forbedre arbeidsflyten din og åpne opp for en mengde muligheter for å skape robuste og funksjonsrike React-applikasjoner .