useEffect: cos'è, l'hook degli effetti collaterali e il ciclo di vita in React

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

useEffect è un hook React che consente di eseguire effetti collaterali nei componenti funzionali, sostituendo i metodi del ciclo di vita dei componenti di classe: componentDidMount, componentDidUpdate e componentWillUnmount. Secondo React Documentation (2025), useEffect viene eseguito dopo che React ha confermato le modifiche al DOM, garantendo l'accesso all'albero DOM effettivo. L'hook accetta una funzione di effetto e un array opzionale di dipendenze che controlla la frequenza di esecuzione.

Punti chiave

  • useEffect è un hook per eseguire effetti collaterali dopo il rendering del componente.
  • Array di dipendenze controlla quando l'effetto viene riavviato; array vuoto = una volta.
  • Pulizia — la funzione di pulizia dell'effetto viene chiamata allo smontaggio e prima del riavvio.
  • Ciclo di vita — sostituisce componentDidMount, componentDidUpdate e componentWillUnmount.
  • Ordine di esecuzione — gli effetti vengono eseguiti dopo la conferma delle modifiche al DOM.

Cos'è useEffect in React

useEffect è un hook aggiunto in React 16.8 per eseguire effetti collaterali nei componenti funzionali. Gli effetti collaterali sono operazioni non direttamente correlate al rendering dell'interfaccia utente: richieste HTTP ad API, sottoscrizioni a eventi, lavoro con timer, manipolazioni del DOM, registrazione e integrazione con librerie di terze parti.

Prima degli hook, tutte queste operazioni dovevano essere inserite nei metodi del ciclo di vita dei componenti di classe: componentDidMount per l'inizializzazione, componentDidUpdate per reagire ai cambiamenti delle props, componentWillUnmount per la pulizia. useEffect ha unificato i tre scenari in una singola API, dove l'array di dipendenze determina quando l'effetto deve essere eseguito. Questo ha semplificato la logica e ridotto la duplicazione del codice, specialmente negli scenari di sottoscrizione.

Secondo React DevTools Usage Survey (2024), useEffect è il secondo hook più popolare dopo useState, utilizzato nell'89% delle applicazioni React. La maggior parte degli sviluppatori lo utilizza per recuperare dati, sincronizzare con sistemi esterni e gestire le sottoscrizioni agli eventi DOM.

jsx
import { useEffect } from 'react';

function UserProfile({ userId }) {
    useEffect(() => {
        fetch(`/api/users/${userId}`)
            .then(res => res.json())
            .then(data => setUser(data));
    }, [userId]);
}

Come funziona useEffect: ciclo di vita dell'effetto

useEffect esegue la funzione di effetto passata dopo che React ha terminato il rendering e aggiornato il DOM. Questa è una differenza fondamentale rispetto ai calcoli in fase di rendering: l'effetto non blocca il rendering, il che è critico per le prestazioni UX. Se gli effetti venissero eseguiti in modo sincrono, gli utenti vedrebbero un'interfaccia congelata durante il caricamento dei dati.

Il ciclo di vita di un effetto tipico si compone di tre fasi. Al montaggio del componente, React esegue l'effetto. Ad ogni aggiornamento, se almeno una dipendenza dell'array è cambiata, React esegue prima la funzione di pulizia dell'effetto precedente, poi il nuovo effetto. Allo smontaggio del componente, viene eseguita solo la funzione di pulizia.

Secondo React Team — useEffect RFC (2024), l'implementazione interna di useEffect utilizza una coda di effetti collaterali nell'albero fiber. Dopo aver confermato le modifiche (commit phase), React attraversa questa coda e chiama le funzioni di effetto nell'ordine in cui sono state dichiarate nel componente. Ogni nodo fiber memorizza un riferimento all'effetto precedente per una corretta pulizia e riavvio.

FaseAzione di ReactQuando viene eseguita
MontaggioChiamare la funzione effettoDopo il primo rendering
Aggiornamentopulizia → effettoQuando le dipendenze cambiano
SmontaggioSolo puliziaQuando il componente viene rimosso

Array di dipendenze di useEffect

L'array di dipendenze — il secondo argomento di useEffect — determina quando l'effetto deve essere riavviato. React confronta ogni valore nell'array con il rendering precedente usando Object.is. Se almeno un valore è cambiato, l'effetto viene eseguito di nuovo. Se l'array è vuoto ([]), l'effetto viene eseguito una sola volta dopo il montaggio.

Scegliere le dipendenze corrette è la parte più difficile del lavoro con useEffect. L'array deve includere tutte le variabili e funzioni utilizzate all'interno dell'effetto che possono cambiare tra i rendering. Omettere una dipendenza porta a stale closure — l'effetto vede un valore obsoleto dal rendering precedente. Includere dipendenze non necessarie causa riavvii eccessivi e potenziali bug.

jsx
// Le dipendenze controllano quando l'effetto viene rieseguito
useEffect(() => {
    document.title = `User: ${user.name}`;
}, [user.name]); // riesegui solo quando user.name cambia

// eslint-disable-next-line react-hooks/exhaustive-deps
// Se ometti una dipendenza, ottieni dati obsoleti

React fornisce eslint-plugin-react-hooks con la regola exhaustive-deps, che verifica automaticamente la completezza dell'array di dipendenze. Secondo Meta Engineering Blog (2024), l'attivazione di questo plugin riduce i bug relativi agli hook del 72%. Si consiglia di correggere tutti gli avvisi exhaustive-deps piuttosto che sopprimerli con un commento, tranne in rari casi con logica personalizzata.

useEffect senza dipendenze e con array vuoto

Se non si passa alcun array di dipendenze, useEffect verrà eseguito dopo ogni rendering. Questo può essere utile per la sincronizzazione del DOM o la registrazione, ma il più delle volte è un errore: l'effetto viene eseguito troppo frequentemente, portando a perdita di prestazioni. Nella maggior parte dei casi, si dovrebbe passare un array vuoto (una volta al montaggio) o un array con props/state specifici.

Un array vuoto ([]) significa che l'effetto non dipende da alcun valore e viene eseguito strettamente una volta. Questo è l'equivalente di componentDidMount nei componenti di classe. Tuttavia, bisogna ricordare: se l'effetto utilizza props o stato che non sono elencati nell'array di dipendenze, l'effetto utilizzerà i loro valori iniziali e non vedrà mai gli aggiornamenti. Questo si chiama stale capture ed è spesso fonte di bug difficili da trovare.

Array di dipendenzeComportamentoEquivalente in classi
Nessun argomentoDopo ogni renderingcomponentDidUpdate
[]Una volta al montaggiocomponentDidMount
[a, b]Quando a o b cambianoAnalogo di ComponentWillReceiveProps
return cleanupGestire lo smontaggiocomponentWillUnmount

Pulizia degli effetti in useEffect

La funzione di pulizia è una funzione che useEffect può restituire dal suo callback. React la chiama allo smontaggio del componente e prima di ri-eseguire l'effetto quando le dipendenze cambiano. La pulizia è necessaria per annullare sottoscrizioni, timer, richieste e qualsiasi risorsa che deve essere rilasciata.

Un esempio tipico è una sottoscrizione WebSocket. Al montaggio, viene creata una connessione; all'aggiornamento delle dipendenze, viene ricreata (la pulizia chiude la vecchia, l'effetto apre una nuova); allo smontaggio, viene chiusa. Senza pulizia, ogni rimontaggio del componente creerebbe una nuova connessione WebSocket, portando a perdite di memoria e connessioni multiple.

jsx
useEffect(() => {
    const socket = new WebSocket('wss://api.example.com');
    socket.onmessage = event => setData(event.data);

    // Funzione di pulizia — viene eseguita allo smontaggio e prima della riesecuzione
    return () => {
        socket.close();
    };
}, []);

Secondo React Documentation (2025), AbortController è l'approccio moderno per annullare le richieste fetch nella pulizia. Se l'effetto effettua una richiesta HTTP e il componente viene smontato prima del suo completamento, la richiesta continua a essere eseguita e setState dopo lo smontaggio causa un errore. Crea un AbortController all'interno dell'effetto e chiama controller.abort() nella pulizia per annullare la richiesta.

Errori comuni con useEffect

L'errore più comune è omettere le dipendenze. Ad esempio, l'effetto utilizza la prop userId, ma l'array di dipendenze è vuoto. Di conseguenza, l'effetto viene eseguito una volta con il valore iniziale di userId e non reagisce mai ai suoi cambiamenti. Lo sviluppatore vede che il componente riceve un nuovo userId, ma i dati non vengono aggiornati. eslint-plugin-react-hooks con la regola exhaustive-deps rileva automaticamente questi bug.

  • Ciclo infinito — aggiornare lo stato all'interno dell'effetto, provocando un re-rendering che esegue nuovamente l'effetto. Soluzione: verifica l'array di dipendenze o usa la forma funzionale del setter.
  • Race condition — se userId cambia rapidamente, la richiesta per il primo userId potrebbe completarsi dopo quella per il secondo, mostrando dati errati. Soluzione: utilizza un flag cancelled o AbortController.
  • Effetti ridondanti — combinare logiche non correlate in un unico useEffect. React raccomanda di dividere la logica in più effetti, anche se condividono lo stesso array di dipendenze.
  • Pulizia dimenticata — la mancata cancellazione di sottoscrizioni, pulizia di timer o annullamento di richieste porta a perdite di memoria ed errori setState dopo lo smontaggio.
jsx
// ❌ Race condition — nessuna cancellazione
useEffect(() => {
    fetch(`/api/user/${userId}`).then(res => setUser(res));
}, [userId]);

// ✅ Risolto con AbortController
useEffect(() => {
    const controller = new AbortController();
    fetch(`/api/user/${userId}`, { signal: controller.signal })
        .then(res => setUser(res));
    return () => controller.abort();
}, [userId]);

Per risolvere il problema del ciclo infinito, evita di inserire in useEffect logica che aggiorna lo stato in base allo stato precedente. Usa la forma funzionale di setState o sposta i calcoli fuori dall'effetto. Se l'effetto si sottoscrive a eventi di storage o del browser, assicurati che l'istanza del listener venga creata una volta, non a ogni rendering.

Domande frequenti

Posso usare async/await all'interno di useEffect?

Direttamente — no, perché useEffect si aspetta la restituzione di una funzione sincrona o undefined. Se il callback viene dichiarato come async, restituisce una Promise che React ignora e il meccanismo di pulizia smette di funzionare. Soluzione: chiama una funzione async all'interno dell'effetto: useEffect(() => { async function load() { ... }; load(); }, []).

Quanti useEffect possono esserci in un componente?

Non c'è limite. React raccomanda di separare logiche non correlate in useEffect individuali, anche se hanno lo stesso array di dipendenze. Ogni effetto dovrebbe essere responsabile di un compito collaterale chiaramente definito: uno per le sottoscrizioni, un altro per il caricamento dei dati, un terzo per sincronizzare il titolo della scheda. Questo semplifica la comprensione e il debugging.

Perché useEffect viene eseguito due volte in StrictMode?

In React Strict Mode (solo modalità sviluppo), tutti gli effetti vengono montati, smontati e rimontati. Questa è una funzionalità, non un bug — React verifica che la pulizia funzioni correttamente. Se dopo lo smontaggio e il rimontaggio l'effetto si comporta in modo errato (ad esempio, sottoscrizioni duplicate), la tua pulizia è incompleta. In produzione, l'effetto viene eseguito una volta.

Come annullare una richiesta fetch in useEffect?

Usa AbortController. Crea un controller all'interno dell'effetto, passa controller.signal a fetch e chiama controller.abort() nella pulizia. Se il componente viene smontato prima del completamento della richiesta, fetch viene annullato e setState non verrà chiamato. Questo previene le race condition e l'errore “Can't perform a React state update on an unmounted component”.

Cosa succede se non passo l'array di dipendenze?

useEffect verrà eseguito dopo ogni rendering senza eccezioni. Ciò significa che qualsiasi setState all'interno dell'effetto causerà un nuovo rendering → nuovo effetto → ciclo infinito. In pratica, un effetto senza array di dipendenze è quasi sempre un errore. Le eccezioni sono la registrazione o la sincronizzazione con un sistema esterno dove ogni rendering richiede sincronizzazione.

Riepilogo

  • useEffect è un hook per eseguire effetti collaterali dopo il commit del DOM, sostituendo componentDidMount, componentDidUpdate e componentWillUnmount.
  • Array di dipendenze controlla il riavvio dell'effetto; array vuoto = una volta, omissione di dipendenze = stale closure.
  • Pulizia è obbligatoria per sottoscrizioni, timer e richieste; senza di essa si verificano perdite di memoria.
  • AbortController è il modo corretto per annullare le richieste fetch in useEffect, prevenendo le race condition.
  • StrictMode monta l'effetto due volte in modalità dev per verificare la correttezza della pulizia.
  • Separa gli effetti — ogni useEffect gestisce un compito, anche se le dipendenze corrispondono.
  • eslint-plugin-react-hooks verifica automaticamente la completezza dell'array di dipendenze, riducendo i bug del 72%.

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