I løbet af mange interviews har jeg bemærket, at selv erfarne programmører har problemer med at skelne mellem Hooks, for slet ikke at tale om deres mere avancerede muligheder. Derfor vil jeg i denne artikel forsøge at forklare, hvordan Hooks skal bruges.
De vigtigste ting, du skal huske om Hooks:
de kan kun bruges i funktionskomponenter - klassekomponenter har deres egen livscyklusimplementering;
De starter altid med brug;
Du kan bruge så mange Hooks, du vil, men du skal huske, at brugen af dem har indflydelse på den samlede ydelse;
de skal udføres i samme rækkefølge ved hver rendering ... men hvorfor? Lad os se på et eksempel:
<code>srcFunctionComponent.js
Linje 11:5: React Krog "useEffect" kaldes betinget. <strong>React-kroge</strong> skal kaldes i nøjagtig samme rækkefølge i hver komponent render .eslintreact-hooks/rules-of-hooks
Som du kan se, er det kun en eslint-advarsel, så du kan deaktivere den ved at tilføje en kommando nedenunder i toppen af filen Funktionskomponent
/* eslint-disable react-hooks/rules-of-hooks */
og det vil virke, men kun indtil vi opfylder den betingelse, der kører vores Hook. Den næste ting, vi vil se, er denne fejl.
Fejl, der ikke blev opdaget: Renderede flere kroge end under den forrige rendering.
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 sker dette? React er afhængig af den rækkefølge, krogene kaldes i, da React ikke ville vide, hvad der skulle returneres for useEffect, fordi der ikke var en sådan krog i linjen at tjekke.
Husk, at eslint er et stærkt værktøj, der hjælper os med at finde mange potentielle bugs og fejl. Det er farligt at deaktivere dens advarsler, så tjek altid, om det kan få appen til at gå ned, hvis du ignorerer advarslen.
useState
Du ved sikkert, hvordan det ser ud 😉.
const [value, setValue] = useState(0);
Så du har 4 elementer: tilstand (reaktiv værdi), opdateringsfunktion (setter), faktisk hook (funktion) og valgfri startværdi. Hvorfor returnerer den et array? Fordi vi kan omstrukturere det, som vi vil.
Nu vil jeg fokusere på det sidste element - den oprindelige værdi. Der er to måder at videregive den oprindelige tilstand på:
Med hardcoded værdi eller andet - som vil blive kaldt ved hver gengivelse
const [value, setValue] = useState(0);
Med en funktionsversion. Det er virkelig nyttigt, hvis vi kun vil køre den indledende tilstand én gang, ved den allerførste gengivelse. Måske er du nødt til at foretage en masse komplekse beregninger for at modtage den oprindelige tilstand? Det vil pænt reducere ressourceomkostningerne, yay!
En anden ting, der kan skabe fejl i app-flowet: Du ved sikkert, hvordan man opdaterer en tilstand, ikke?
setValue(1);
Ja ... men hvad nu, hvis jeg vil opdatere tilstanden ud fra en tidligere tilstand?
setValue(værdi + 1);
Ja... Men nej... Hvad nu, hvis du prøver at kalde setter-funktionen to gange, den ene efter den anden? Den anbefalede måde at opdatere en tilstand på, baseret på den tidligere tilstand, er at bruge en funktion. Det garanterer, at du henviser til den tidligere tilstand
Denne krog tager 2 argumenter (det andet er valgfrit), og vi bruger den til at håndtere bivirkninger. Og afhængigt af, hvad vi sender som det andet argument, vil krogen blive kaldt forskelligt:
uden andet argument - hver gengivelse
useEffect(() => {
gørnoget();
});
tomt array - kun ved første gengivelse
useEffect(() => {
gørnoget();
}, []);
array med afhængigheder - hver gang værdien i afhængighedsarrayet ændres
Med useEffect kan vi bruge noget, der kaldes cleanup. Hvad kan man bruge det til? Det er meget nyttigt, men jeg synes, det er bedst til at rense event-lyttere. Lad os sige, at du vil oprette en event-lytter, som afhænger af en eller anden tilstand. Du ønsker ikke at tilføje en ny event-lytter ved hver tilstandsændring, for efter nogle få renderinger vil der være så mange lyttere, at det vil påvirke appens ydeevne. En god måde at undgå sådanne ting på er at bruge oprydningsfunktionen. Hvordan gør man det? Du skal bare tilføje en returfunktion til useEffect.
Fordi det er inde i useEffect Hook, kaldes return afhængigt af dependency array - ved hver rendering, kun ved den første rendering, eller når værdien i dependency array ændres. Men når komponenten afmonteres, vil cleaning blive kaldt på det andet argument uanset hvad. Returneringen Kode kaldes før den egentlige kode fra Hook. Det er meget logisk - først renser du den gamle, så opretter du en ny. Er det ikke rigtigt?
Til at begynde med ser det ok ud. Du henter nogle data, og når dataene kommer, opdaterer du tilstanden. Og her er fælden:
Nogle gange vil du modtage en sådan advarsel: Kan ikke udføre en React-tilstandsopdatering på en afmonteret komponent. Dette er en no-op, men det indikerer en hukommelseslækage i din applikation. Det kan løses ved at annullere alle abonnementer og asynkrone opgaver i en useEffect-oprydningsfunktion.
Årsagen er, at komponenten kan afmonteres i mellemtiden, men appen vil stadig forsøge at opdatere komponentens tilstand, efter at løftet er opfyldt. Hvordan håndterer man det? Du skal tjekke, om komponenten findes.
Bemærk: Der findes en meget lignende krog => useLayoutEffect() - tilbagekaldet kører efter rendering af komponenten, men før dom'en opdateres visuelt. Det er nyttigt, når du arbejder med getBoundingClientRect(), men du bør bruge useEffect som standard. Hvorfor det? Fordi det kan blokere visuelle opdateringer - når du har en kompleks kode inde i din effekt Hook.
brugKontekst
Hvad kan man bruge det til? Deling af data uden at sende props. Består af følgende elementer:
I child skal du importere konteksten og kalde useContext Hook og sende konteksten som et argument.
import { UserContext } fra "./App";
const { navn } = useContext(UserContext);
return <h1>Hej {navn}<>
```
Voilà. Det ser fedt ud. Mest til overførsel af globale data som temaer osv. Anbefales ikke til brug i opgaver med meget dynamiske ændringer.
Vi kan selvfølgelig oprette en brugerdefineret kontekstudbyder og en brugerdefineret krog for at reducere boilerplate i stedet ... men jeg vil beskæftige mig med brugerdefinerede kroge i den næste artikel.
useReducer
Den giver os mulighed for at styre tilstanden og gengive den, når den ændres - ligesom useState. Det svarer til redux reducer. Denne er bedre end useState, når tilstandslogikken er mere kompliceret.
Hvornår skal man bruge det? Når vi ønsker at opnå referentiel lighed (og dermed reducere antallet af oprettede funktioner). Denne krog returnerer funktionen, i modsætning til useMemo, som returnerer værdien.
Eksempel: Opret en funktion i den overordnede komponent, og send den derefter via props
Tjek derefter i den underordnede komponent, hvor mange gange effekten Hook vil blive kaldt efter tilføjelse af funktionen til afhængighedsarrayet:
// Barn
useEffect(() => {
console.log("getSquaredValue", getSquaredValue());
}, [getSquaredValue]);
Den vil logge på konsollen ved hver gengivelse! Selv hvis værdierne inde i getSquaredValue() funktion blev ikke ændret. Men vi kan undgå dette ved at pakke funktionen ind i useCallback
Det er ikke neutralt, når man ser på ressourceomkostningerne - useMemo skal kaldes ved hver gengivelse, den gemmer værdien i hukommelsen og sammenligner (hukommelsesoverhead),
bruger Memoization - optimeringsteknikken, en specifik form for caching.
Du bør kun bruge den i to scenarier:
Hvis du vil undgå at kalde en kompleks kode ved hver gengivelse;
Hvis du vil opnå referencemæssig lighed.
Lad os se lidt nærmere på det andet tilfælde. Vi vil bruge useEffect med et objekt som en afhængighed. Da objekter sammenlignes ved hjælp af deres reference, vil useEffect blive kaldt ved hver gengivelse. For at undgå den slags kan vi kombinere useEffect med useMemo for at memorere sådanne objekter og derefter sende de memorerede objekter til dependency-arrayet. Et kort eksempel:
Objektet 'hobbit' får afhængighederne af useEffect-krogen (linje 49) til at ændre sig ved hver rendering. Flyt det ind i useEffect-tilbagekaldet. Alternativt kan du pakke initialiseringen af 'hobbit' ind i sin egen useMemo ()-krog.eslintreact-hooks/exhaustive-deps
Den vigtigste ting: useRef udløser ikke genrendering (som useState), fordi den ikke er forbundet med renderingscyklussen - den beholder den samme reference mellem renderinger.
const ref = useRef(0);
For at kalde den gemte værdi skal du bruge en aktuel egenskab (ref er et objekt) -. ref.nuværende
Det andet tilfælde, hvor vi kan bruge denne krog, er til at henvise til elementer i HTML. Hvert element har en ref-attribut. Så vi kan håndtere fokus, begivenheder osv.
Det tredje tilfælde er, at vi kan bruge refs til at håndtere ukontrollerede komponenter. Du kan læse mere om dem i react-dokumenter, Men kort fortalt ser det sådan her ud:
Som du kan se, er der ingen eventhandler, den husker bare den indtastede værdi. Det er godt til at håndtere grundlæggende formularer, hvor du bare vil læse gemte værdier, når du har brug for dem (f.eks. ved indsendelse).
Bonus: Det er fantastisk, når du har brug for at huske tidligere tilstandsværdier. Du kan bruge useEffect-krogen til det, bare send tilstanden til ref.
Som du kan se, er Hooks ikke så indlysende. Vi kan kombinere dem til at løse mange problemer. Du vil helt sikkert få stor gavn af at studere dette emne.
Og der er også brugerdefinerede kroge ...
Afslutningsvis, React-kroge har revolutioneret den måde React-udviklere tilgang til bygning webapplikationer . Ved at give en mere intuitiv og effektiv måde at styre tilstand og livscyklus på i funktionelle komponenter er hooks blevet en integreret del af React udvikling .
Uanset om du er en erfaren udvikler eller lige er startet med React, er det afgørende at forstå de mest populære hooks og deres anvendelsesmuligheder. Med hooks som useState, useEffect, useContext m.fl, React-komponenter kan bygges med renere og mere genanvendelig kode. Desuden er muligheden for at skabe Tilpassede kroge gør det muligt for udviklere at indkapsle og dele logik på tværs af flere komponenter, hvilket fremmer genanvendelighed og modularitet i koden. Efterhånden som React fortsætter med at udvikle sig og introducere nye funktioner, vil hooks utvivlsomt spille en central rolle i udnyttelsen af rammens fulde potentiale.
Så uanset om du arbejder på en lille funktionsapplikation eller en storstilet webapplikation, er det vigtigt at omfavne React-kroge vil forbedre dit udviklingsworkflow og åbne op for et væld af muligheder for at skabe robuste og funktionsrige React-applikationer .