Articolo originale: Learn React Hooks – A Beginner's Guide di Victor Ikechukwu

Tradotto e adattato da: Angelo Mirabelli

I componenti funzionali non erano sempre il metodo preferito per dichiarare i componenti in React.

Prima dell'introduzione di React versione 16.8, i componenti funzionali erano trattati in modo molto simile ai cittadini di seconda classe. Non erano in grado di gestire lo stato, la logica e molte altre funzionalità di React e le abbiamo utilizzate solo per il rendering di componenti molto semplici nell'interfaccia utente.

React versione 16.8 ha risolto questi problemi introducendo gli Hook in React, che consentono agli sviluppatori di utilizzare queste funzionalità di React nei componenti funzionali.

In questo articolo imparerai:

  • Cosa sono gli Hook di React
  • Quattro comuni Hook di React con esempi di come scriverli nelle tue applicazioni
  • Infine, daremo un'occhiata a come scrivere i tuoi Hook di React personalizzati

Gli hook sono funzioni integrate di React introdotte nella versione 16.8. Consentono di utilizzare le funzionalità della libreria React come i metodi del ciclo di vita, lo stato e il contesto nei componenti funzionali senza doversi preoccupare di riscriverli in una classe.

Ogni nome degli Hook di React è preceduto dalla parola "use". Ad esempio, useState o useEffect. Questo formato è stato scelto perché gli Hook consentono agli sviluppatori di utilizzare le funzionalità speciali della libreria React. Quindi stai usando ( use) quella caratteristica speciale della libreria di React.

Perché usare gli Hook di React?

Molti sviluppatori sono scettici sull'apprendimento degli Hook di React. Ma tu non dovresti esserlo. Ecco alcuni motivi per cui dovresti iniziare a usare gli Hook di React:

Le classi in React possono creare confusione

Le classi sono un ostacolo all'apprendimento corretto di React. Per usarli, devi capire come funziona la parola chiave this. È inoltre necessario ricordare costantemente di associare i gestori di eventi, nonché altri metodi ridondanti incontrati quando si lavora con le classi in React.

I componenti classe sono complessi e possono essere difficili da capire

I componenti classe sono generalmente di grandi dimensioni e cercano di eseguire molte operazioni. A lungo andare, diventano difficili da capire.

Gli hook risolvono questo problema consentendo di separare componenti di grandi dimensioni in varie funzioni più piccole, anziché dover forzare tutta la logica in un unico componente.

Gli Hook hanno componenti più corti e una migliore leggibilità

I componenti classe sono dotati di molto codice standard. Considera il componente Contatore qui seguito:

class Contatore extends Component {
    constructor(props) {
        super(props)
        this.state = {
        	conto: 1,
        }
    }
    render() {
        return (
            <div>
                Il Conteggio Attuale: {this.state.conto}
                <div>
                <button onClick={this.setState({ conto: this.state.conto + 1 })}>
                addiziona
                </button>
                <button onClick={this.setState({ conto: this.state.conto - 1 })}>
                sottrai
                </button>
                </div>
            </div>
    );
    }
}

Ecco il codice equivalente che utilizza il componente funzionale e React Hooks:

function Contatore ()  {
    const [conto, setConto] = useState(1);
    return (
        <div>
            Il Conteggio Attuale: {this.state.conto}
            <div>
                <button onClick={() => setConto(conto + 1)}>addiziona</button>
                <button onClick={() => setConto(conto - 1)}>sottrai</button>
            </div>
        </div>
    );
};

Nota come il componente della classe sia molto più complesso. Hai bisogno di una classe per estendere React, un costruttore per inizializzare lo stato e devi fare riferimento alla parola chiave this ovunque.

L'uso di componenti funzionali rimuove molto di questo, quindi il nostro codice diventa più breve e più facile da leggere e mantenere.

Regole per l'uso degli Hook di React

Quando si utilizzano gli Hook di React ci sono alcune regole a cui attenersi:

  • Chiama solo hook al livello superiore di un componente : non dovresti usare hook all'interno di loop, condizioni o funzioni nidificate. Invece, usa sempre Hook al livello più alto della tua funzione React, prima di qualsiasi parola chiave di ritorno.
  • Chiama solo hook da React Functions : non chiamare mai hook da normali funzioni JavaScript. Puoi:
    ✅ Chiamare Hook dai componenti funzionali di React.
    ✅ Chiama Hook da Hook personalizzati.

Hook di React più comuni

Ad oggi, React ha 10 hook integrati. Diamo un'occhiata ai quattro più comuni:

  • useState
  • useEffect
  • useContext
  • useReducer

L'Hook useState

L'Hook useState consente di creare, aggiornare e manipolare lo stato all'interno dei componenti funzionali.

React ha questo concetto di stato, che sono variabili che contengono dati da cui dipendono i nostri componenti e che possono cambiare nel tempo. Ogni volta che queste variabili cambiano, React aggiorna l'interfaccia utente eseguendo nuovamente il rendering del componente nel DOM con i valori correnti delle variabili di stato.

L'hook accetta un singolo argomento opzionale: un valore iniziale per lo stato. Quindi restituisce una matrice di due valori:

  • La variabile di stato
  • Una funzione per aggiornare lo stato

Come esempio, diamo un'occhiata a un componente contatore:

Per utilizzare un Hook, il primo passo è importare l'Hook nella parte superiore del file:

import { useState } from "react";

Quindi, inizializza Hook con un valore. Poiché restituisce un array, puoi utilizzare la destrutturazione dell'array per accedere ai singoli elementi nell'array, in questo modo:

const [conto, setConto] = useState(0);

Con ciò, il codice del componente sarà:

import { useState } from "react";

function Contatore() {
    // Dichiara una nuova variabile di stato, che chiameremo "conto"
    const [conto, setConto] = useState(0);
    return (
        <div>
        Current Cart Count: {count}
            <div>
            <button onClick={() => setConto(conto - 1)}>Add to cart</button>
            <button onClick={() => setConto(conto + 1)}>Remove from cart</button>
            </div>
        </div>
    );
}

Ecco come apparirà il componente una volta renderizzato.

Contatore

Facendo clic sul pulsante Add to cart o Remove from cart, il valore del conteggio della variabile di stato cambierà e il componente verrà visualizzato nuovamente con il valore aggiornato dello stato.

L'Hook useEffect

Se hai familiarità con i metodi del ciclo di vita della classe React, puoi pensare a l'Hook  useEffect come ai metodi del ciclo di vita componentDidMount, componentDidUpdate, e componentWillUnmount tutti combinati in un'unica funzione. Ti consente di replicare i metodi del ciclo di vita di React nei componenti funzionali.

L'Hook useEffect ti consente di eseguire effetti collaterali nei componenti delle funzioni. Gli effetti collaterali sono azioni che possono essere eseguite insieme alle operazioni principali di un componente, come le interazioni con API esterne, la modifica delle variabili di stato e il recupero dei dati.

L'hook useEffect accetta 2 argomenti:

  • Una funzione con il codice da eseguire
  • Un array che contiene un elenco di valori dall'ambito del componente (props, contesto e variabili di stato), noto come array di dipendenza, che dice a l'Hook di essere eseguito ogni volta che il suo valore viene aggiornato. Se non viene fornito, l'Hook verrà eseguito dopo ogni rendering.

Ecco un esempio di utilizzo di Hook:

import { useState, useEffect } from "react";
function Contatore() {
    // Dichiara variabili di stato
    const [conto, setConto] = useState(0);
    const [prodotto, setProdotto] = useState("Eggs");
    useEffect(() => {
    	console.log(`${product} will rule the world!`);
    });
    return (
        <div>
        Current {product}'s count: {conto}
            <div>
                <button onClick={() => setConto(conto + 1)}>Add to cart</button>
                <button onClick={() => setconto(conto - 1)}>Remove from cart</button>
                Change Product:{" "}
                <input type="text" onChange={(e) => setProdotto(e.target.value)} />
            </div>
        </div>
    );
}

Nell'esempio, l'effetto verrà eseguito dopo ogni aggiornamento dello stato.

Effetto predefinito
wAAAAAAAAAIdjI8JkO231psw0iuv3rz7D4biSJbmiabqyrbuVgAAOw ==

Come attivare condizionalmente un Effetto

Per eseguire l'Hook solo quando determinati valori sono cambiati, passare le variabili come dipendenza nell'array:

useEffect(() => {
	console.log(`${product} will rule the world!`);
}, [prodotto]); // Eseguire nuovamente l'effetto solo se il valore del prodotto cambia

Con questa modifica, Hook verrà eseguito solo al primo rendering e quando il valore del prodotto viene modificato.

Matrice di dipendenza dagli effetti

Come eseguire una volta al primo rendering

Se vuoi che un effetto venga eseguito solo una volta al primo rendering, come fare chiamate API quando il componente viene renderizzato per la prima volta, puoi passare un array vuoto come sua dipendenza in questo modo:

useEffect(() => {
	console.log("Questo viene eseguito una volta al primo rendering");
}, []);

Fornendo un array vuoto, dice a Hook di rimanere in ascolto per zero cambiamenti di stato, quindi verrà eseguito solo una volta.

L'Hook useContext

L'Hook useContext funziona con l'API React Context. Fornisce un modo per rendere accessibili dati particolari a tutti i componenti dell'applicazione, indipendentemente dalla loro profondità di annidamento.

React ha un flusso di dati unidirezionale, in cui i dati possono essere passati solo da genitore a figlio. Per passare i dati (come lo stato) da un componente padre a un componente figlio, dovrai passarli manualmente come prop attraverso vari livelli a seconda di quanto profondamente è nidificato il componente figlio.

Per dati come la lingua preferita dall'utente, il tema o le proprietà dell'utente autenticato, è noioso doverli passare manualmente nell'albero dei componenti.

L'API Context di React e l'Hook useContext semplificano il passaggio dei dati tra tutti i componenti dell'app.

Accetta un oggetto di contesto creato utilizzando React.createContext e restituisce il contesto corrente in questo modo:

const valore = useContext(QualcheContesto);

Diamo un'occhiata a un esempio di come funziona l'Hook:

Innanzitutto, crea un contesto per utilizzare l'Hook. Ad esempio, ecco un UserContext per ottenere il valore degli utenti correnti:

import React from "react";
// alcuni valori di contesto fittizi
const utenti = [
{
    nome: "Harry Potter",
    occupazione: "Wizard",
},
{
    nome: "Kent Clark",
    occupazione: "Super hero,
},
];

export const UserContext = React.createContext(utenti);

Ogni contesto ha un wrapper Provider, che consente ai suoi componenti figli di sottoscrivere le modifiche nel contesto e trasmette il valore del contesto attraverso un valore prop.

Se il valore prop del provider viene aggiornato, i suoi componenti figlio ad esso collegato, verranno nuovamente visualizzati con il nuovo valore di contesto.

function Utenti() {
return (
    <UserContext.Provider valore={utenti}>
    <UserProfile />
    </UserContext.Provider>
);
}

Nell'esempio, UserProfile viene resa come componente di consumo del contesto.

import React, { useContext } from "react";
import { UserContext } from "./App";

export function UserProfile() {
    const utenti = useContext(UserContext);
    return (
        <div>
            {users.map((utente) => (
            <li>
            I am {utente.nome} and I am a {utente.occupazione
            ))}
        </div>
    );
}

Questo visualizzerà le proprietà degli utenti correnti:

zrquu592NphAAAAAElFTkSuQmCC

L'Hook useReducer

L'Hook useReducer è un'alternativa all'Hook  useState. La differenza è che consente una logica più complessa e aggiornamenti di stato che coinvolgono più sottovalori.

Simile a useState, useReducer ti consente di creare variabili simili a uno stato che aggiornano l'interfaccia utente ogni volta che cambiano.

Questo Hook accetta 2 argomenti: una funzione riduttore e uno stato iniziale.

useReducer(riduttore, statoIniziale);

Restituisce una matrice di due valori che possono essere destrutturati nel valore corrente dello stato e una funzione di invio.

const [stato, spedizione] = useReducer(riduttore, statoIniziale);

Impariamo i suoi argomenti e i valori restituiti:

  • stato : questo è il valore corrente di statoIniziale passato all'Hook.
  • riduttore : il riduttore è una funzione che accetta lo stato e un'azione. Sulla base di questi argomenti determina come cambierà il valore di stato.
  • spedizione: la funzione di spedizione è il modo in cui passiamo un'azione alla funzione di riduzione. Invia l'azione da utilizzare per aggiornare lo stato.

In genere, ripetiamo il tipo di azioni eseguite nella nostra app tramite un'istruzione switch per determinare come cambierà il valore dello stato. Ecco come Hook aggiorna i valori del suo stato.

function riduttore(stato, azione) {
    switch (azione.type) {
        case "CASE_1":
        return {
        	aggiornaStato,
        };
        case "CASE_2":
        return {
        	aggiornaStato,
        };
        default:
        	return stato;
    }
}

La funzione di spedizione di solito invia un oggetto nel formato:

spedizione({ type: "ACTION_TYPE", payload: argomentiOpzionali });

Dove type è la descrizione dell'azione e payload sono gli argomenti che vuoi passare al riduttore.

Come creare Hook personalizzati

Un Hook personalizzato è l'idea di estrarre la logica dei componenti comunemente usati dall'interfaccia utente in funzioni JavaScript utilizzando gli Hook di React già disponibili. Questo ti aiuta a prevenire la duplicazione del codice e ti consente di rendere tale logica riutilizzabile all'interno di più componenti.

Diamo un'occhiata a un esempio di hook personalizzato che restituirà una risposta da qualsiasi URL API valido che gli passiamo.

//useFetch.js
import { useState, useEffect } from "react";

export function useFetch(url) {
	//values
    const [data, setData] = useState(null);
    const [error, setError] = useState("");
    useEffect(() => {
        fetch(url)
        .then(res => {
            if (!res.ok) {
            throw Error("qualcosa di sbagliato, non è stato possibile connettersi alla risorsa");
        }
        setData(res.json());
        })
        .then(() => {
        	setError("");
        })
        .catch( error => {
            console.warn(`scusa si è verificato un errore, dovuto a ${error.message} `);
            setData(null);
            setError(error.message);
        });
    }, [url]);
    return [data, error];
}

Ora puoi usare questa logica ovunque nella tua app semplicemente importando la funzione e passando un percorso API come argomento, invece di scrivere tutto da zero.

Ricapitolando

Spero che tu abbia compreso quanto sono utili gli Hook di React. Ti consentono di creare al volo componenti efficaci senza preoccuparti dei problemi che derivano dall'uso dei componenti di classe.

Dal permetterti di concentrarti sulla scrittura del tuo codice principale al permetterti di creare i tuoi Hook personalizzati… Gli Hook di React sono così fantastici! Sono entusiasta che li possa provare tu stesso.

Se hai trovato utile questo articolo, condividilo con i tuoi amici e la tua rete. Inoltre, sentiti libero di connetterti con me su Twitter e sul mio blog dove condivido una vasta gamma di articoli e risorse didattici gratuite.

Grazie per la lettura e buona codifica!