Monien haastattelujen aikana olen huomannut, että jopa kokeneilla ohjelmoijilla on ongelmia koukkujen erottamisessa, puhumattakaan niiden kehittyneemmistä ominaisuuksista. Yritän siis selittää tässä artikkelissa, miten koukkuja tulisi käyttää.
Tärkeimmät asiat, jotka sinun on muistettava koukuista:
niitä voidaan käyttää vain funktiokomponenteissa - luokkakomponenteilla on oma elinkaaritoteutus;
ne alkavat aina käytä;
voit käyttää niin monta koukkua kuin haluat, mutta sinun on muistettava, että niiden käyttö vaikuttaa kokonaissuorituskykyyn;
ne on suoritettava samassa järjestyksessä jokaisessa renderöinnissä... mutta miksi? Katsotaanpa esimerkkiä:
<code>srcFunctionComponent.js
Rivi 11:5: React Koukkua "useEffect" kutsutaan ehdollisesti. <strong>React Koukut</strong> on kutsuttava täsmälleen samassa järjestyksessä jokaisessa komponentissa renderöi .eslintreact-hooks/rules-of-hooks
Kuten näet, se on vain eslint-varoitus, joten voit poistaa sen käytöstä lisäämällä komennon alhaalla olevan komennon alkuun FunctionComponent
/* eslint-disable react-hooks/rules-of-hooks */
ja se toimii, mutta vain siihen asti, kunnes täytämme ehdon, joka ohjaa Koukkuamme. Seuraava asia, jonka näemme, on tämä virhe.
Epäonnistunut virhe: Renderöitiin enemmän koukkuja kuin edellisen renderöinnin aikana.
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
Miksi näin tapahtuu? React luottaa Koukkujen kutsumisjärjestykseen, koska React ei tietäisi, mitä palauttaa useEffectin kohdalla, koska rivillä ei ollut tällaista Koukkua, jota olisi pitänyt tarkistaa.
Muista, että eslint on tehokas työkalu, joka auttaa meitä löytämään paljon mahdollisia vikoja ja virheitä. Sen varoitusten poistaminen käytöstä on vaarallista, tarkista aina, voiko varoituksen huomiotta jättäminen aiheuttaa sovelluksen kaatumisen.
useState
Tiedät varmaan, miltä se näyttää 😉.
const [value, setValue] = useState(0);
Sinulla on siis neljä elementtiä: tila (reaktiivinen arvo), päivitysfunktio (asettaja), varsinainen koukku (funktio) ja valinnainen alkuarvo. Miksi se palauttaa array? Koska voimme järjestää sen uudelleen haluamallamme tavalla.
Nyt haluan keskittyä viimeiseen elementtiin - alkuarvoon. Alkutila voidaan siirtää kahdella tavalla:
Kovakoodatulla arvolla tai jollakin muulla - jota kutsutaan jokaisella renderöinnillä.
const [value, setValue] = useState(0);
Toimintoversiolla. Se on todella hyödyllinen, jos haluamme suorittaa alkutilan vain kerran, heti ensimmäisellä renderöinnillä. Ehkä sinun täytyy tehdä paljon monimutkaisia laskutoimituksia saadaksesi alkutilan? Se vähentää mukavasti resurssikustannuksia, jee!
Toinen asia, joka voi aiheuttaa virheitä sovelluksen virtaukseen: tiedät varmaan, miten tila päivitetään, eikö niin?
setValue(1);
Aivan... mutta entä jos haluan päivittää tilan edellisen tilan perusteella?
setValue(arvo + 1);
Kyllä... Mutta ei... Entä jos yrität kutsua setterifunktiota kahdesti peräkkäin? Suositeltava tapa päivittää tila edellisen tilan perusteella on käyttää funktiota. Se takaa, että viittaat edelliseen tilaan.
Tämä Hook ottaa 2 argumenttia (toinen on valinnainen), ja käytämme sitä sivuvaikutusten käsittelyyn. Ja riippuen siitä, mitä annamme toisena argumenttina, koukkua kutsutaan eri tavalla:
ilman toista argumenttia - jokainen renderöinti
useEffect(() => {
doSomething();
});
tyhjä array - vain ensimmäisellä renderöinnillä
useEffect(() => {
doSomething();
}, []);
joukko riippuvuuksia - aina kun riippuvuusjoukon arvo muuttuu.
useEffect(() => {
doSomething(arvo);
}, [arvo]);
Siivous
UseEffectin avulla voimme käyttää jotain, mitä kutsutaan siivoukseksi. Mitä varten se on? Se on erittäin hyödyllinen, mutta mielestäni se sopii parhaiten tapahtumakuuntelijoiden puhdistamiseen. Oletetaan, että haluat luoda tapahtumakuuntelija, joka riippuu jostain tilasta. Et halua lisätä uutta tapahtumakuuntelijaa jokaisella tilan muutoksella, koska muutaman renderöinnin jälkeen kuuntelijoita on niin paljon, että se vaikuttaa sovelluksen suorituskykyyn. Hyvä tapa välttää tällainen on käyttää cleanup-ominaisuutta. Miten se tehdään? Lisää vain palautusfunktio useEffect.
Koska se on useEffect-koukun sisällä, paluuta kutsutaan riippuvuusjoukon mukaan - jokaisella renderöinnillä, vain ensimmäisellä renderöinnillä tai kun riippuvuusjoukon arvo muuttuu. Mutta kun komponentti irrotetaan, puhdistusta kutsutaan toisesta argumentista riippumatta. Paluu koodi kutsutaan ennen varsinaista Hookin koodia. Se on hyvin loogista - ensin puhdistetaan vanha ja sitten luodaan uusi. Eikö niin?
Aluksi se näyttää ihan hyvältä. Haet tietoja, ja kun tiedot tulevat, päivität tilan. Ja tässä on ansa:
Joskus saat tällaisen varoituksen: React:n tilapäivitystä ei voi tehdä irrotetulle komponentille. Tämä ei onnistu, mutta se osoittaa, että sovelluksessasi on muistivuoto. Korjaa ongelma peruuttamalla kaikki tilaukset ja asynkroniset tehtävät useEffect-puhdistustoiminnossa.
Syynä on se, että komponentti voidaan irrottaa sillä välin, mutta sovellus yrittää silti päivittää kyseisen komponentin tilan lupauksen täyttymisen jälkeen. Miten sitä käsitellään? Sinun on tarkistettava, onko komponentti olemassa.
Huomautus: On olemassa hyvin samanlainen Hook => useLayoutEffect() - takaisinkutsu suoritetaan komponentin renderöinnin jälkeen, mutta ennen kuin dom päivitetään visuaalisesti. Se on hyödyllinen työskenneltäessä getBoundingClientRect():n kanssa, mutta sinun tulisi käyttää oletusarvoisesti useEffectiä. Miksi? Koska se voi estää visuaaliset päivitykset - kun sinulla on monimutkaista koodia efektikoukun sisällä.
useContext
Mitä varten se on? Tietojen jakaminen ilman rekvisiittaa. Koostuu seuraavista elementeistä:
Luotu konteksti - tiedot
Kontekstin tarjoaja - tarjoa konteksti kaikille lapsille
Lapsessa sinun on tuotava konteksti ja kutsuttava useContext-koukkua ja annettava konteksti argumenttina.
import { UserContext } from "./App";
const { name } = useContext(UserContext);
return <h1>Hei {nimi}<>
```
Voilà. Näyttää siistiltä. Lähinnä globaalien tietojen kuten teemojen jne. välittämiseen. Ei suositella käytettäväksi tehtävissä, joissa on hyvin dynaamisia muutoksia.
Tietenkin voimme luoda mukautetun kontekstin tarjoajan ja mukautetun koukun vähentämään sen sijaan boilerplatea... mutta käsittelen mukautettuja koukkuja seuraavassa artikkelissa.
useReducer
Sen avulla voimme hallita tilaa ja renderöidä uudelleen, kun tila muuttuu - kuten useState. Se on samanlainen kuin redux reducer. Tämä on parempi kuin useState, kun tilalogiikka on monimutkaisempi.
Mitä varten se on? Sitä voidaan käyttää, kun tila halutaan palauttaa alkuarvoonsa. Alla on mukava esimerkki:
// Vanhempi
// Lapsi
function init(initialNumber) {
return { number: initialNumber };
}
function reducer(state, action) {
switch (action.type) {
case "change":
{ number: Math.random() };
case "reset":
return init(action.payload);
default:
heittää uuden Error();
}
}
export default function ChildComponent({ getFactorial }) {
const [state, dispatch] = useReducer(reducer, initialNumber, init);
return (
<>
<h2>Numero: {state.number}</h2>
<button
onclick="{()" > dispatch({ type: "reset", payload: initialNumber })}
>
Reset
</button>
<button onclick="{()" > dispatch({ type: "change" })}>Draw</button>
</>
);
}
Numero: {state.number}
useCallback
Milloin sitä käytetään? Kun haluamme saavuttaa viittauksellisen tasa-arvon (ja vähentää näin luotujen funktioiden määrää). Tämä Koukku palauttaa funktion, toisin kuin useMemo, joka palauttaa arvon.
Esimerkki: Luo funktio emokomponenttiin ja siirrä se sitten rekvisiitan kautta.
Tarkista sitten lapsikomponentista, kuinka monta kertaa efekti Hookia kutsutaan sen jälkeen, kun toiminto on lisätty riippuvuusjoukkoon:
// Lapsi
useEffect(() => {
console.log("getSquaredValue", getSquaredValue());
}, [getSquaredValue]);
Se kirjautuu konsoliin jokaisesta renderöinnistä! Vaikka arvot sisällä getSquaredValue() toiminto ei muuttunut. Voimme kuitenkin välttää tämän käärimällä kyseisen funktion useCallbackiin.
Se ei ole neutraali, kun tarkastellaan resurssikustannuksia - useMemoa on kutsuttava jokaisen renderöinnin yhteydessä, se tallentaa arvon muistiin ja vertaa sitä (muistin yleiskustannus),
käyttää Memoization - optimointitekniikka, erityinen muoto välimuistiin.
Sitä tulisi käyttää vain kahdessa tilanteessa:
Jos haluat estää monimutkaisen koodin kutsumisen jokaisella renderöinnillä;
Jos haluat saavuttaa viittauksellisen tasa-arvon.
Tarkastellaan hieman tarkemmin toista tapausta. Haluamme käyttää useEffectia, jossa on objekti riippuvuussuhteena. Koska objekteja verrataan niiden viitteen perusteella, useEffectiä kutsutaan jokaisella renderöinnillä. Välttääksemme tällaiset asiat voimme yhdistää useEffectin ja useMemon, jotta voimme memoida tällaiset objektit ja sitten siirtää nämä memoidut objektit riippuvuusjoukkoon. Lyhyt esimerkki:
Hobbit-olio saa useEffect-koukun (rivi 49) riippuvuudet muuttumaan jokaisen renderöinnin yhteydessä. Siirrä se useEffect-kutsun sisään. Vaihtoehtoisesti voit kietoa 'hobbitin' alustuksen omaan useMemo ()-koukkuunsa.eslintreact-hooks/exhaustive-deps
Tärkein asia: useRef ei käynnistä uudelleenrenderöintiä (kuten useState), koska se ei ole yhteydessä renderöintisykliin - se säilyttää saman viittauksen renderöintien välillä.
const ref = useRef(0);
Jos haluat kutsua tallennettua arvoa, sinun on käytettävä nykyistä ominaisuutta (ref on objekti) - ref.current
Toinen tapaus, jossa voimme käyttää koukkua, on viittaaminen HTML:n sisällä oleviin elementteihin. Jokaisella elementillä on ref-attribuutti. Voimme siis käsitellä fokusta, tapahtumia jne.
Kolmas tapaus on, että voimme käyttää refs:ää hallitsemattomien komponenttien käsittelyyn. Voit lukea niistä lisää kohdasta react docs, mutta lyhyesti sanottuna se näyttää tältä:
Kuten näet, tapahtumankäsittelijää ei ole, vaan se vain muistaa kirjoitetun arvon. Se sopii hyvin peruslomakkeiden käsittelyyn, kun haluat vain lukea tallennetut arvot, kun tarvitset niitä (kuten lähetettäessä).
Bonus: Se on hyvä, kun sinun täytyy muistaa aiemmat tila-arvot. Voit käyttää sitä varten useEffect-koukkua, kunhan vain annat tilan ref:lle.
Kuten huomaat, koukut eivät ole niin ilmeisiä. Voimme yhdistää niitä monien ongelmien ratkaisemiseksi. Voit varmasti hyötyä suuresti tämän aiheen opiskelusta.
Lisäksi on olemassa mukautettuja koukkuja...
Yhteenvetona, React koukut ovat mullistaneet React-kehittäjät lähestymistapa rakentamiseen verkkosovellukset . Tarjoamalla intuitiivisemman ja tehokkaamman tavan hallita toiminnallisten komponenttien tilaa ja elinkaarta, koukuista on tullut olennainen osa työkaluja. React kehitys .
Olitpa kokenut kehittäjä tai vasta aloittamassa React:n käyttöä, suosituimpien koukkujen ja niiden käyttötapausten ymmärtäminen on ratkaisevan tärkeää. Koukkujen, kuten useState, useEffect, useContext, ja muiden koukkujen avulla, React-komponentit voidaan rakentaa puhtaammalla ja uudelleenkäytettävämmällä koodilla. Lisäksi kyky luoda mukautetut koukut avulla kehittäjät voivat kapseloida ja jakaa logiikkaa useiden komponenttien kesken, mikä edistää koodin uudelleenkäytettävyyttä ja modulaarisuutta. Kun React kehittyy edelleen ja ottaa käyttöön uusia ominaisuuksia, koukuilla on epäilemättä keskeinen rooli kehyksen koko potentiaalin hyödyntämisessä.
Olipa kyseessä sitten pieni toiminnallinen sovellus tai laajamittainen verkkosovellus, on tärkeää, että otat käyttöön React koukut parantaa kehitystyönkulkuasi ja avaa lukemattomia mahdollisuuksia luoda vankkoja ja ominaisuuksiltaan monipuolisia React-sovellukset .