Migliori pratiche con React Hook
Pubblicato: 2022-03-10 I React Hooks sono una nuova aggiunta in React 16.8 che ti consente di utilizzare lo stato e altre funzionalità di React senza scrivere un componente di class
. In altre parole, gli Hook sono funzioni che ti consentono di "agganciare" le funzionalità dello stato React e del ciclo di vita dai componenti della funzione. (Non funzionano all'interno dei componenti class
.)
React fornisce alcuni hook integrati come useState
. Puoi anche creare i tuoi hook per riutilizzare il comportamento con stato tra diversi componenti. L'esempio seguente mostra un contatore il cui stato è gestito utilizzando l' useState()
. Ogni volta che fai clic sul pulsante, utilizziamo setCount()
per aggiornare il valore di count
di 1
.
Questo esempio esegue il rendering di un contatore con un valore di 0
. Quando si fa clic sul pulsante, il valore viene incrementato di 1
. Il valore iniziale del componente viene definito utilizzando useState
.
const [count, setCount] = useState(0)
Come puoi vedere, lo impostiamo su 0
. Quindi utilizziamo il metodo onClick()
per chiamare setCount
quando vogliamo incrementare il valore.
<button onClick={() => setCount(count + 1)}> Click me </button>
Prima del rilascio di React Hooks, questo esempio avrebbe utilizzato più righe di codice, poiché avremmo dovuto utilizzare un componente di class
.
Regole di reazione ai ganci
Prima di approfondire le best practices, è necessario comprendere le regole di React Hooks che sono anche alcuni dei concetti fondamentali delle pratiche presentate in questo articolo.
I React Hooks sono funzioni JavaScript, ma devi seguire due regole quando le usi.
- Chiama Hooks al livello più alto;
- Chiama gli Hook solo dai componenti di React.
Nota : queste due regole sono state introdotte in React Hooks, invece di far parte di JavaScript stesso.
Diamo un'occhiata a queste regole in modo più dettagliato.
Ganci di chiamata al livello più alto
Non chiamare Hook all'interno di loop, condizioni o funzioni nidificate. Usa sempre gli Hooks al livello più alto della tua funzione React. Seguendo questa regola, ti assicuri che gli Hook siano chiamati nello stesso ordine ogni volta che un componente esegue il rendering. Questo è ciò che consente a React di preservare correttamente lo stato di Hooks tra più chiamate useState
e useEffect
.
Creiamo un componente Form
che avrà due stati:
-
accountName
-
accountDetail
Questi stati avranno valori predefiniti, utilizzeremo l'hook useEffect
per mantenere lo stato nella memoria locale del nostro browser o nel titolo del nostro documento.
Ora, questo componente sarà forse in grado di gestire correttamente il suo stato se rimane lo stesso tra più chiamate di useState
e useEffect
.
function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }
Se l'ordine dei nostri Hook cambia (cosa possibile quando vengono chiamati in loop o condizionali), React avrà difficoltà a capire come preservare lo stato del nostro componente.
// ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...
Questo è l'ordine che React segue per chiamare i nostri hook. Poiché l'ordine rimane lo stesso, sarà in grado di preservare lo stato del nostro componente. Ma cosa succede se mettiamo una chiamata Hook all'interno di una condizione?
// We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }
La accountName !== ''
è true
al primo rendering, quindi eseguiamo questo Hook. Tuttavia, al prossimo rendering l'utente potrebbe cancellare il modulo, rendendo la condizione false
. Ora che saltiamo questo Hook durante il rendering, l'ordine delle chiamate Hook diventa diverso:
useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect
React non saprebbe cosa restituire per la seconda chiamata useState
Hook. React prevedeva che la seconda chiamata Hook in questo componente corrisponda all'effetto persistForm
, proprio come durante il rendering precedente, ma non è più così. Da quel momento in poi, anche ogni successiva chiamata Hook
dopo quella che abbiamo saltato si sposterebbe di uno, portando a bug.
Per questo motivo Hooks deve essere chiamato al livello più alto dei nostri componenti. Se vogliamo eseguire un effetto in modo condizionale, possiamo inserire quella condizione all'interno del nostro Hook.
Nota : controlla i documenti di React Hook per saperne di più su questo argomento.
Chiamate hook solo da componenti React
Non chiamare Hook da normali funzioni JavaScript. Invece, puoi chiamare Hooks dai componenti della funzione React. Diamo un'occhiata alla differenza tra la funzione JavaScript e il componente React di seguito:
Funzione JavaScript
import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;
Qui importiamo l'hook useState
dal pacchetto React, quindi dichiariamo la nostra funzione. Ma questo non è valido in quanto non è un componente React.
Funzione di reazione
import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );
Anche se il corpo di entrambi sembra simile, quest'ultimo diventa un componente quando importiamo React nel file. Questo è ciò che ci consente di utilizzare cose come JSX e ganci React all'interno.
Se ti è capitato di importare il tuo hook preferito senza importare React (il che lo rende una funzione regolare), non sarai in grado di utilizzare l'Hook che hai importato poiché l'Hook è accessibile solo nel componente React.
Hook di chiamata da hook personalizzati
Un Hook personalizzato è una funzione JavaScript il cui nome inizia con use
e che può chiamare altri Hook. Ad esempio, useUserName
viene utilizzato sotto un Hook personalizzato che chiama gli useState
e useEffect
. Recupera i dati da un'API, scorre i dati e chiama setIsPresent()
se il nome utente specifico che ha ricevuto è presente nei dati dell'API.
export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }
Possiamo quindi continuare a riutilizzare la funzionalità di questo hook in altri luoghi in cui ne abbiamo bisogno nella nostra applicazione. In tali luoghi, tranne quando necessario, non è più necessario chiamare useState
o useEffect
.
Seguendo questa regola, ti assicuri che tutta la logica con stato in un componente sia chiaramente visibile dal suo codice sorgente.
Plugin ESLint
Il plugin ESLint chiamato eslint-plugin-react-hooks
applica le regole di cui sopra. Questo è utile per far rispettare le regole quando si lavora su un progetto. Ti suggerisco di utilizzare questo plugin quando lavori al tuo progetto, specialmente quando lavori con gli altri. Puoi aggiungere questo plugin al tuo progetto se desideri provarlo:
// Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }
Questo plugin è incluso per impostazione predefinita nell'app Create React. Quindi non è necessario aggiungerlo se esegui il bootstrap delle tue applicazioni React utilizzando Create-React-App.
Pensare in ganci
Diamo una breve occhiata ai componenti della class
e ai componenti funzionali (con Hooks), prima di approfondire le poche best practices di Hooks.
Il modo più semplice per definire un componente in React è scrivere una funzione JavaScript che restituisca un elemento React:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
Il componente Welcome
accetta props
che è un oggetto che contiene dati e restituisce un elemento React. Possiamo quindi importare e rendere questo componente in un altro componente.
Il componente class
utilizza una metodologia di programmazione chiamata Encapsulation che sostanzialmente significa che tutto ciò che è rilevante per il componente di classe vivrà al suo interno. I metodi del ciclo di vita ( constructors
, componentDidMount()
, render
e così via) forniscono ai componenti una struttura prevedibile.
L'incapsulamento è uno dei fondamenti dell'OOP ( O bject- O riented P rogramming). Si riferisce al raggruppamento di dati all'interno dei metodi che operano su tali dati e viene utilizzato per nascondere i valori o lo stato di un oggetto di dati strutturati all'interno di una classe, impedendo l'accesso diretto di parti non autorizzate ad essi.
Con Hooks, la composizione di un componente cambia dall'essere una combinazione di Hook del ciclo di vita a funzionalità con alcuni rendering alla fine.
Componente di funzione
L'esempio seguente mostra come utilizzare ganci personalizzati in un componente funzionale (senza mostrare che cos'è il corpo). Tuttavia, ciò che fa o può fare non è limitato. Potrebbe essere l'istanziazione di variabili di stato, il consumo di contesti, l'iscrizione del componente a vari effetti collaterali o tutto quanto sopra se stai utilizzando un hook personalizzato!
function { useHook{...}; useHook{...}; useHook{...}; return (
...); }
Componente di classe
Un componente di class
richiede l'estensione da React.Component
e la creazione di una funzione di render
che restituisca un elemento React. Ciò richiede più codice ma ti darà anche alcuni vantaggi.
class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }
Ci sono alcuni vantaggi che ottieni utilizzando i componenti funzionali in React:
- Sarà più facile separare i componenti contenitore e di presentazione perché devi pensare di più allo stato del tuo componente se non hai accesso a
setState()
nel tuo componente. - I componenti funzionali sono molto più facili da leggere e testare perché sono semplici funzioni JavaScript senza stato o hook del ciclo di vita.
- Finisci con meno codice.
- Il team di React ha affermato che potrebbe esserci un aumento delle prestazioni per i componenti funzionali nelle future versioni di React.
Questo porta alla prima best practice quando si utilizzano React Hooks.
Best Practices di Hooks
1. Semplifica i tuoi ganci
Mantenere React Hooks semplice ti darà il potere di controllare e manipolare efficacemente ciò che accade in un componente per tutta la sua vita. Evita il più possibile di scrivere Hook personalizzati ; puoi inline a useState()
o useEffect()
invece di creare il tuo hook.
Se ti ritrovi a utilizzare una serie di Hook personalizzati correlati nella funzionalità, puoi creare un hook personalizzato che funge da wrapper per questi. Diamo un'occhiata a due diversi componenti funzionali con i ganci di seguito.
Componente funzionale v1
function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
Componente funzionale v2
function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
v2 è una versione migliore perché mantiene l'hook semplice e tutti gli altri useHook
sono in linea di conseguenza. Questo ci consente di creare funzionalità che possono essere riutilizzate su diversi componenti e ci dà anche più potere per controllare e manipolare i nostri componenti in modo efficace. Invece di adottare la v1 in cui i nostri componenti sono disseminati di Hooks, dovresti usare la v2 che renderà il debug facile e il tuo codice più pulito.
2. Organizza e struttura i tuoi ganci
Uno dei vantaggi di React Hooks è la possibilità di scrivere meno codice di facile lettura. In alcuni casi, la quantità di useEffect()
e useState()
può ancora creare confusione. Quando mantieni organizzato il tuo componente, ti aiuterà nella leggibilità e manterrà il flusso dei tuoi componenti coerente e prevedibile. Se i tuoi Hook personalizzati sono troppo complicati, puoi sempre suddividerli in Hook sub-personalizzati. Estrai la logica del tuo componente in Hook personalizzati per rendere leggibile il tuo codice.
3. Usa gli snippet di React Hooks
React Hooks Snippets è un'estensione di Visual Studio Code per rendere React Hooks più semplice e veloce. Attualmente sono supportati cinque hook:
-
useState()
-
useEffect()
-
useContext()
-
useCallback()
-
useMemo()
Sono stati aggiunti anche altri frammenti. Ho provato a lavorare con questi Hook ed è stata una delle migliori pratiche che ho usato personalmente mentre lavoravo con loro.
Esistono due modi per aggiungere frammenti di React Hooks al tuo progetto:
- Comando
Avvia VS Code Quick open ( Ctrl + P ), incollaext install ALDuncanson.react-hooks-snippets
e premi Invio . - Mercato di estensione
Avvia "VS Code Extension Marketplace" ( Ctrl + Maiusc + X ) e cerca "React Hook Snippets". Quindi, cerca l'icona "Alduncanson".
Consiglio il primo frammento. Leggi di più sugli snippet qui o controlla gli ultimi frammenti di Hooks qui.
4. Prendere in considerazione le regole di Hooks
Sforzati di tenere sempre in considerazione le due regole degli Hook che abbiamo imparato in precedenza mentre lavoriamo con React Hooks.
- Chiama i tuoi Hook solo al livello più alto. Non chiamare Hook all'interno di loop, condizioni o funzioni nidificate.
- Chiama sempre Hook dai componenti della funzione React o da Hook personalizzati, non chiamare Hook da normali funzioni JavaScript.
Il plugin ESlint chiamato eslint-plugin-react-hooks
applica queste due regole, puoi aggiungere questo plugin al tuo progetto se lo desideri come spieghiamo sopra nella sezione regole degli hook.
Le migliori pratiche non sono state completamente risolte perché gli Hook sono ancora relativamente nuovi. Quindi l'adozione dovrebbe essere presa con precauzione che si prenderebbe adottando in qualsiasi tecnologia primitiva. Con questo in mente, gli Hooks sono la strada per il futuro di React.
Conclusione
Spero che questo tutorial ti sia piaciuto. Abbiamo imparato le due regole più importanti di React Hooks e come pensare in modo efficace in Hooks. Abbiamo esaminato i componenti funzionali e alcune best practice per scrivere Hooks nel modo giusto ed efficace. Per quanto brevi siano le regole, è importante renderle la tua bussola guida quando scrivi le regole. Se sei incline a dimenticarlo, puoi utilizzare il plug-in ESLint per applicarlo.
Spero che tu possa seguire tutte le lezioni apprese qui nel tuo prossimo progetto React. Buona fortuna!
Risorse
- "Presentazione di Hooks", React Docs
- "Componenti funzionali e di classe in reazione", David Joch, Medium
- "Mixine considerate nocive", Dan Abramov, React Blog
- "React Hooks: best practices e un cambiamento di mentalità", Bryan Manuele, Medium
- "React Hooks Snippet per VS Code", Anthony Davis, Visual Code Marketplace