React Hooks — cosa sono, hook principali e regole di utilizzo

Autore: IT Sectr Pubblicato: 2026-07-04 Tempo di lettura: 10 min

React Hooks sono funzioni che consentono di utilizzare stato, effetti, contesto e altre funzionalità di React in componenti funzionali, senza scrivere classi. Introdotti in React 16.8, gli hook hanno radicalmente cambiato l’approccio allo sviluppo, sostituendo pattern complessi come HOC e render props. Secondo React, 2024, esistono 15 hook integrati che coprono tutti gli scenari di gestione dei componenti.

Punti chiave

  • Hook — funzioni per collegare le funzionalità di React a componenti funzionali senza extends Component.
  • useState — l’hook base per la gestione dello stato, restituisce un valore e un setter.
  • useEffect — per effetti collaterali: richieste API, sottoscrizioni, timer, manipolazioni DOM.
  • useContext — per accedere al contesto React senza wrapper Consumer e static contextType.
  • Regole degli hook — chiamare solo al livello superiore e solo all’interno di componenti funzionali o hook personalizzati.

Cosa sono i React Hooks?

React Hooks sono un insieme di funzioni integrate in React che permettono di “collegarsi” ai meccanismi interni del framework senza creare classi. Prima di React 16.8, i componenti funzionali potevano solo accettare props e restituire JSX — qualsiasi logica complessa richiedeva un componente classe.

Il problema dei componenti classe è la suddivisione della logica correlata. Il codice relativo a una stessa entità (ad esempio, una sottoscrizione WebSocket) era forzatamente suddiviso tra componentDidMount, componentDidUpdate e componentWillUnmount. Gli hook risolvono questo: tutta la logica viene raggruppata in un unico useEffect.

Il secondo problema è il riutilizzo della logica. Per riutilizzare la logica di stato tra componenti classe, bisognava applicare HOC (Componenti di Ordine Superiore) o render props — entrambi i pattern creavano annidamento extra nell’albero dei componenti. Gli hook personalizzati risolvono questo senza annidamento.

useState — Gestione dello stato

useState è l’hook più basilare. Prende un valore iniziale e restituisce una tupla: il valore corrente e una funzione per aggiornarlo. A differenza di this.setState nelle classi, useState non fonde gli oggetti — il nuovo stato sostituisce completamente il precedente per una specifica chiamata useState.

js
import React, { useState } from 'react';

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

Forma funzionale di setState

Il setter di useState può accettare una funzione che riceve il valore precedente e restituisce uno nuovo. La forma funzionale è obbligatoria quando il nuovo stato viene calcolato dal precedente e sono possibili chiamate setState raggruppate — ogni chiamata riceverà il valore precedente corrente.

useEffect — Effetti collaterali e ciclo di vita

useEffect è un hook per eseguire effetti collaterali nei componenti funzionali. Prende due argomenti: una funzione effetto e un array di dipendenze. React esegue l’effetto dopo ogni render, ma quando vengono specificate le dipendenze — solo quando una di esse cambia.

Un array di dipendenze vuoto [] significa che l’effetto viene eseguito una volta dopo il primo render (analogo a componentDidMount). Restituire una funzione dall’effetto è una pulizia che viene eseguita allo smontaggio (analogo a componentWillUnmount) e prima di rieseguire l’effetto.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // Pulizia - chiudi socket
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

Le dipendenze di useEffect sono l’unica connessione tra l’effetto e il mondo esterno. Se l’effetto utilizza una variabile da props o stato, deve essere nell’array di dipendenze. Ignorare questa regola è fonte di bug con closure obsolete (stale closures).

useContext — Accesso al contesto

useContext è un hook per leggere i valori del contesto. Prende un oggetto contesto creato da React.createContext e restituisce il valore corrente. Se il contesto cambia, il componente si ri-renderizza automaticamente con il nuovo valore.

Prima di useContext, accedere al contesto nei componenti funzionali richiedeva un avvolgimento in Context.Consumer, che creava annidamento. useContext elimina completamente Consumer — basta chiamare l’hook in qualsiasi punto del componente funzionale.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('chiaro');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext non è un sostituto di Redux o dello stato globale. React raccomanda di usare il contesto per valori che cambiano raramente — tema, locale, stato di autenticazione. Per dati aggiornati frequentemente, ogni re-render ricalcolerà tutti i consumatori del contesto, il che può ridurre le prestazioni.

useReducer — Logica di stato complessa

useReducer è un’alternativa a useState per stati con logica di aggiornamento complessa. Prende una funzione riduttrice e uno stato iniziale, restituisce lo stato corrente e una funzione dispatch. Il riduttore riceve lo stato corrente e un’azione, restituisce un nuovo stato — una funzione pura senza effetti collaterali.

useReducer è particolarmente utile quando più azioni (set, reset, increment, addItem) gestiscono un unico stato. Invece di molteplici useState con diversi setter — un unico riduttore con tipi di azione chiari. Questo rende la logica prevedibile e facilmente testabile.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — Ottimizzazione

useRef crea un oggetto mutabile che persiste tra i render. Modificare current non attiva un re-render. Gli usi principali sono l’accesso agli elementi DOM e la memorizzazione di valori mutabili (timer, valori precedenti, istanze di librerie).

useMemo memoizza il risultato di una funzione. Ricalcola il valore solo quando una dipendenza cambia. Usalo per calcoli costosi — filtraggio di grandi array, ordinamento, formattazione dati. useCallback è un caso speciale di useMemo per memoizzare funzioni.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // Autofocus al mount
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Memoizza risultato filtrato
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // Memoizza callback
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

Una regola importante: useRef, useMemo e useCallback sono strumenti di ottimizzazione, non costrutti obbligatori. Non avvolgere tutto in useMemo — misura prima le prestazioni. L’ottimizzazione prematura complica il codice. React renderizza i componenti rapidamente; useMemo è necessario solo quando i calcoli sono veramente costosi (O(n²) e superiori).

Regole degli hook ed errori comuni

React ha introdotto due regole rigorose per gli hook. Prima: chiama gli hook solo al livello superiore — non all’interno di condizioni, cicli o funzioni annidate. Seconda: chiama gli hook solo da componenti funzionali React o hook personalizzati. Il plugin ESLint eslint-plugin-react-hooks verifica automaticamente entrambe le regole.

L’errore più comune è violare l’ordine di chiamata degli hook. React si basa sull’ordine di chiamata degli hook tra i render. Se un hook si trova all’interno di una condizione e non viene eseguito in un render, tutti gli hook successivi si spostano, causando bug.

ErroreCosa succedeSoluzione
Hook in una condizioneL’ordine degli hook si rompeSposta la logica condizionale all’interno dell’hook
Stale closureL’effetto usa un valore vecchioAggiungi tutte le dipendenze all’array
Ciclo infinitouseEffect senza dipendenze modifica lo statoSpecifica le dipendenze o usa useReducer
Mutazione di ref nel renderEffetto collaterale nel corpo della funzioneSposta le mutazioni in useEffect

Il secondo errore comune è stale closure in useEffect. Se l’effetto usa una variabile non specificata nelle dipendenze, l’effetto “cattura” il suo valore al momento della creazione della closure. La soluzione è includere sempre tutte le variabili utilizzate nell’array di dipendenze. Se ci sono troppe dipendenze, considera di dividere l’effetto in più parti.

Domande frequenti

Perché gli hook non possono essere chiamati all’interno di condizioni?

React si basa sull’ordine di chiamata degli hook tra i render. Se un hook viene chiamato all’interno di una condizione e non si attiva in un render, tutti gli hook successivi si spostano — il loro stato si mescola. La regola ESLint hooks/exhaustive-deps avvisa su questo.

Qual è la differenza tra useEffect e useLayoutEffect?

useLayoutEffect è sincrono e viene eseguito prima che il browser disegni le modifiche. useEffect è asincrono — dopo il disegno. Usa useLayoutEffect solo quando devi misurare o modificare il DOM prima che l’utente veda le modifiche (posizione popover, ripristino dello scroll).

Come annullare una richiesta fetch allo smontaggio?

Usa AbortController all’interno di useEffect. Crea un controller, passa il signal a fetch e chiama controller.abort() nella funzione di pulizia. Per browser vecchi, usa un flag cancelled: return () => { cancelled = true; } con un controllo prima di setState.

Cos’è un hook personalizzato e quando crearne uno?

Un hook personalizzato è una funzione JavaScript con il prefisso use che utilizza hook integrati. Creane uno quando la stessa logica con hook si ripete in due o più componenti. Esempi: useDebounce, useLocalStorage, useMediaQuery. Gli hook personalizzati sostituiscono HOC e render props.

Perché useEffect viene eseguito due volte in Strict Mode?

In Strict Mode, React monta e smonta intenzionalmente il componente due volte in sviluppo per trovare bug con effetti non puliti. Se la pulizia è scritta correttamente, la doppia chiamata non causa problemi. Ciò non accade in modalità produzione.

Riepilogo

  • React Hooks — funzioni per utilizzare stato, effetti e contesto in componenti funzionali, sostituendo le classi.
  • useState — hook base per stato locale con un setter funzionale per aggiornamenti sicuri.
  • useEffect — hook universale per effetti collaterali con array di dipendenze e funzione di pulizia.
  • useContext — accesso diretto al contesto React senza wrapper Consumer e annidamento extra.
  • useReducer — per logica di stato complessa con tipi di azione, un’alternativa a Redux all’interno di un singolo componente.
  • useRef, useMemo, useCallback — strumenti di ottimizzazione: riferimenti DOM, memoizzazione di valori e callback.
  • Regola del livello superiore — restrizione rigorosa di chiamare hook al di fuori di condizioni, cicli e funzioni annidate.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche