Uno sguardo più approfondito ai ganci React più popolari
Pawel Rybczynski
Software Engineer
Nel corso di molte interviste, ho notato che anche i programmatori più esperti hanno difficoltà a distinguere gli hook, per non parlare delle loro capacità più avanzate. Per questo motivo, in questo articolo cercherò di spiegare come devono essere utilizzati gli hook.
Le cose più importanti da ricordare sui ganci:
possono essere utilizzati solo nei componenti funzionali - i componenti di classe hanno una propria implementazione del ciclo di vita;
iniziano sempre con utilizzo;
si possono usare tutti gli agganci che si vogliono, ma bisogna ricordare che il loro uso ha un impatto sulle prestazioni complessive;
devono essere eseguiti nello stesso ordine su ogni rendering... ma perché? Vediamo un esempio:
<code>srcFunctionComponent.js
Riga 11:5: React Il gancio "useEffect" è chiamato in modo condizionato. <strong>React Ganci</strong> deve essere chiamato esattamente nello stesso ordine in ogni componente render .eslintreact-hooks/rules-of-hooks
Come si può vedere, si tratta solo di un avviso di eslint, quindi è possibile disabilitarlo aggiungendo un comando dal basso all'inizio del file FunzioneComponente
/* eslint-disable react-hooks/rules-of-hooks */
e funzionerà, ma solo finché non verrà soddisfatta la condizione che fa funzionare il nostro Hook. La cosa successiva che vedremo è questo errore.
Errore non corretto: Renderizzati più ganci rispetto al rendering precedente.
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
Perché questo accade? L'React si basa sull'ordine in cui vengono chiamati gli hook, in quanto l'React non saprebbe cosa restituire per l'useEffect perché non c'è un hook nella riga da controllare.
Ricordate che eslint è uno strumento potente, che ci aiuta a individuare molti potenziali bug ed errori. Disattivare i suoi avvisi è una cosa pericolosa, controllate sempre se ignorare l'avviso può causare un crash dell'applicazione.
Stato d'uso
Probabilmente sapete come si presenta 😉
const [value, setValue] = useState(0);
Quindi, ci sono 4 elementi: stato (valore reattivo), funzione di aggiornamento (setter), aggancio effettivo (funzione) e valore iniziale opzionale. Perché restituisce un array? Perché possiamo ristrutturarlo come vogliamo.
Ora voglio concentrarmi sull'ultimo elemento: il valore iniziale. Esistono due modi per passare lo stato iniziale:
Con un valore predefinito o altro, che verrà richiamato a ogni rendering.
const [value, setValue] = useState(0);
Da una versione di funzione. È molto utile se si vuole eseguire lo stato iniziale solo una volta, al primo rendering. Forse è necessario eseguire molti calcoli complessi per ricevere lo stato iniziale? In questo modo si riduce il costo delle risorse, evviva!
Un'altra cosa che può creare bug nel flusso dell'app: probabilmente sapete come aggiornare uno stato, giusto?
setValue(1);
Giusto... ma se volessi aggiornare lo stato in base a uno stato precedente?
setValue(valore + 1);
Sì... Ma no... E se si cerca di chiamare la funzione setter due volte, una dopo l'altra? Il modo consigliato per aggiornare uno stato in base allo stato precedente è utilizzare una funzione. Garantisce che si stia facendo riferimento allo stato precedente
setValue((prevState) => prevState + 1);
// con gli oggetti:
setUser((prevState) => ({ ...prevState, lastName: "Brzeczyszczykiewicz" }));
usaEffetto
Questo hook accetta due argomenti (il secondo è opzionale) e lo usiamo per gestire gli effetti collaterali. A seconda di ciò che passiamo come secondo argomento, l'hook sarà chiamato in modo diverso:
senza secondo argomento - ogni rendering
useEffect(() => {
doSomething();
});
array vuoto - solo al primo rendering
useEffect(() => {
doSomething();
}, []);
con le dipendenze - ogni volta che il valore nell'array delle dipendenze cambia
Con useEffect, possiamo usare qualcosa che viene chiamato cleanup. A cosa serve? È molto utile, ma credo sia meglio per pulire gli ascoltatori di eventi. Supponiamo di voler creare un ascoltatore di eventi che dipende da alcuni stati. Non si vuole aggiungere un nuovo ascoltatore di eventi a ogni cambio di stato, perché dopo qualche rendering ci saranno così tanti ascoltatori da influire sulle prestazioni dell'applicazione. Un ottimo modo per evitare queste cose è usare la funzione di pulizia. Come fare? Basta aggiungere una funzione di ritorno a useEffect.
Poiché si trova all'interno dell'hook useEffect, il ritorno viene chiamato a seconda dell'array di dipendenze: a ogni rendering, solo al primo rendering o quando il valore nell'array di dipendenze cambia. Ma quando il componente viene smontato, la pulizia sarà chiamata sul secondo parametro, indipendentemente da ciò. Il ritorno codice viene richiamato prima del codice effettivo di Hook. È molto logico: prima si pulisce quello vecchio, poi se ne crea uno nuovo. Giusto?
All'inizio sembra tutto a posto. Si recuperano alcuni dati e, quando questi arrivano, si aggiorna lo stato. Ed ecco la trappola:
A volte si riceve un avviso di questo tipo: Impossibile eseguire un aggiornamento di stato React su un componente non montato. Si tratta di un'operazione non necessaria, ma indica una perdita di memoria nell'applicazione. Per risolvere, annullare tutte le sottoscrizioni e le attività asincrone in una funzione di pulizia useEffect.
Il motivo è che il componente può essere smontato nel frattempo, ma l'applicazione cercherà comunque di aggiornare lo stato del componente dopo che la promessa è stata mantenuta. Come comportarsi? È necessario verificare se il componente esiste.
Nota: esiste un hook molto simile => useLayoutEffect() - il callback viene eseguito dopo il rendering del componente, ma prima che la dom venga aggiornata visivamente. È utile quando si lavora con getBoundingClientRect(), ma si dovrebbe usare useEffect per impostazione predefinita. Perché? Perché può bloccare gli aggiornamenti visivi, quando si ha un codice complesso all'interno dell'effetto Hook.
usaContext
A cosa serve? Condividere dati senza passare oggetti di scena. Consiste nei seguenti elementi:
Contesto creato - dati
Fornitore di contesto - fornire un contesto a tutti i bambini
In child, è necessario importare il contesto e chiamare l'hook useContext, passando il contesto come argomento.
importare { UserContext } da "./App";
const { name } = useContext(UserContext);
restituire <h1>Ciao {nome}<>
```
Voilà. Sembra bello. Soprattutto per passare dati globali come temi, ecc. Non è raccomandato per l'uso in attività con modifiche molto dinamiche.
Naturalmente, possiamo creare un fornitore di contesto personalizzato e un hook personalizzato per ridurre il boilerplate... ma tratterò gli hook personalizzati nel prossimo articolo.
usaRiduttore
Ci consente di gestire lo stato e di renderizzare nuovamente quando lo stato cambia, come useState. È simile al redux reducer. È meglio di useState quando la logica dello stato è più complicata.
Quando usarlo? Quando si vuole ottenere l'uguaglianza referenziale (riducendo così il numero di funzioni create). Questo hook restituisce la funzione, a differenza di useMemo che restituisce il valore.
Esempio: Creare una funzione nel componente padre e poi passarla tramite gli oggetti di scena
Verrà registrato nella console a ogni rendering! Anche se i valori all'interno del campo getSquaredValue() non è stata modificata. Ma possiamo evitarlo avvolgendo la funzione in useCallback
Non è neutrale se si considerano i costi delle risorse: useMemo deve essere richiamato a ogni rendering, salva il valore in memoria e lo confronta (overhead di memoria),
utilizza la Memoization, una tecnica di ottimizzazione, una forma specifica di caching.
Dovreste usarlo solo in due scenari:
Se si vuole evitare di richiamare un codice complesso a ogni rendering;
Se si vuole ottenere l'uguaglianza referenziale.
Vediamo un po' più da vicino il secondo caso. Vogliamo usare useEffect con un oggetto come dipendenza. Poiché gli oggetti sono confrontati in base al loro riferimento, useEffect sarà richiamato a ogni rendering. Per evitare questo, possiamo combinare useEffect con useMemo per memorizzare tali oggetti e poi passare gli oggetti memorizzati all'array delle dipendenze. Breve esempio:
L'oggetto 'hobbit' fa cambiare le dipendenze del gancio useEffect (riga 49) a ogni rendering. Spostarlo all'interno del callback useEffect. In alternativa, avvolgere l'inizializzazione di 'hobbit' nel proprio hook useMemo ().eslintreact-hooks/exhaustive-deps
La cosa più importante è che useRef non attiva il re-rendering (come useState) perché non è collegato al ciclo di rendering: mantiene lo stesso riferimento tra i rendering.
const ref = useRef(0);
Per richiamare il valore salvato, è necessario utilizzare una proprietà current (ref è un oggetto) - corrente
Il secondo caso in cui possiamo usare questo hook è per fare riferimento a elementi all'interno dell'HTML. Ogni elemento ha un attributo ref. Quindi, possiamo gestire il focus, gli eventi e così via.
Il terzo caso è quello in cui possiamo usare i refs per gestire componenti non controllati. Si può leggere di più su di essi in documenti di react, ma, in breve, si presenta così:
Come si può vedere, non c'è un gestore di eventi, ma solo la memorizzazione del valore digitato. È ottimo per gestire i moduli di base, quando si vuole solo leggere i valori salvati quando se ne ha bisogno (come al momento dell'invio).
Bonus: è ottimo quando si ha bisogno di ricordare i valori di uno stato precedente. Si può usare il gancio useEffect, basta passare lo stato al ref.
Come si può vedere, i ganci non sono così ovvi. Possiamo combinarli per risolvere molti problemi. Sicuramente trarrete grandi benefici dallo studio di questo argomento.
E ci sono anche ganci personalizzati...
In conclusione, Ganci React hanno rivoluzionato il modo in cui Sviluppatori React approccio all'edificio applicazioni web . Fornendo un modo più intuitivo ed efficiente per gestire lo stato e il ciclo di vita dei componenti funzionali, i ganci sono diventati parte integrante del sistema di gestione delle risorse. Sviluppo React .
Sia che siate sviluppatori esperti o che abbiate appena iniziato a usare l'React, la comprensione dei ganci più popolari e dei loro casi d'uso è fondamentale. Con ganci come useState, useEffect, useContext e altri ancora, Componenti React possono essere costruiti con codice più pulito e riutilizzabile. Inoltre, la possibilità di creare ganci personalizzati consente agli sviluppatori di incapsulare e condividere la logica tra più componenti, favorendo la riusabilità e la modularità del codice. Man mano che React continuerà a evolversi e a introdurre nuove funzionalità, gli agganci svolgeranno senza dubbio un ruolo centrale nello sfruttare appieno il potenziale del framework.
Quindi, sia che si stia lavorando a una piccola applicazione funzionale o a un'applicazione web su larga scala, abbracciare Ganci React migliorerà il vostro flusso di lavoro di sviluppo e aprirà una pletora di possibilità per la creazione di prodotti robusti e ricchi di funzionalità. Applicazioni React .