useContext: essenza, l'hook di accesso al contesto e i provider in React

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

useContext è un hook React che fornisce ai componenti funzionali accesso diretto ai dati di un contesto creato tramite createContext. Il contesto in React risolve il problema del props drilling — passare props attraverso molti componenti intermedi che non utilizzano questi dati direttamente. Secondo la React Documentation (2025), useContext accetta un oggetto contesto e restituisce il valore corrente impostato dal Provider più vicino sopra nell'albero dei componenti. Quando il valore nel Provider cambia, tutti i componenti che utilizzano useContext vengono automaticamente rirenderizzati.

Punti chiave

  • useContext — hook per leggere un valore dal contesto React senza props drilling.
  • createContext — crea un oggetto contesto con un valore predefinito e un componente Provider.
  • Provider — componente wrapper che trasmette il valore del contesto a tutti gli elementi figli.
  • Rirenderizzazione — la modifica del valore del Provider provoca la rirenderizzazione di tutti i consumatori del contesto.
  • Salto dei componenti intermedi — useContext permette di passare dati attraverso diversi livelli di annidamento.

Cos'è useContext in React

useContext è un hook aggiunto in React 16.8 insieme ad altri hook che permette di leggere un valore dal contesto React. Il contesto è un meccanismo integrato in React progettato per trasmettere dati attraverso l'albero dei componenti senza dover passare manualmente props a ogni livello. useContext sostituisce il componente Consumer della vecchia Context API e rende il codice più conciso e leggibile.

I casi d'uso tipici del contesto includono temi (chiaro/scuro), impostazioni locali e traduzioni (i18n), autenticazione utente, impostazioni dell'applicazione e qualsiasi altro dato globale di cui molti componenti a diversi livelli di annidamento hanno bisogno. Il team di React raccomanda di usare il contesto per dati che sono globali per un sottoalbero di componenti, ma non per l'intera applicazione.

Secondo il React Team — Documentazione del contesto (2025), l'uso errato del contesto è una delle principali cause di problemi di prestazioni nelle applicazioni React. Ogni modifica del valore nel Provider provoca una rirenderizzazione di tutti i consumatori, indipendentemente da quale parte dei dati sia cambiata. L'ottimizzazione tramite useMemo e la suddivisione dei contesti risolve questo problema.

jsx
import { createContext, useContext } from 'react';

// Creare contesto con valore predefinito
const ThemeContext = createContext('chiaro');

function ThemedButton() {
    const theme = useContext(ThemeContext);
    return <button className={`btn-${theme}`}>Click</button>;
}

Come funziona il contesto in React

Il meccanismo del contesto in React è implementato tramite il pattern Provider-Consumer. createContext restituisce un oggetto con due entità: Provider — un componente che trasmette il valore, e l'oggetto contesto stesso, che viene utilizzato in useContext. Il Provider viene montato nell'albero dei componenti e trasmette il valore a tutti gli elementi figli indipendentemente dalla profondità di annidamento.

Quando React incontra una chiamata useContext, percorre l'albero fiber alla ricerca del Provider più vicino per quel contesto. Se viene trovato un Provider, viene restituito il suo valore. Se non viene trovato alcun Provider, viene restituito il valore predefinito passato a createContext. Questa ricerca avviene a ogni renderizzazione, ma grazie alla memoizzazione dei nodi fiber è molto veloce e non influisce sulle prestazioni.

Secondo React — Interni del contesto (2024), l'implementazione interna di useContext utilizza una lista collegata di hook, simile a useState. Ogni hook memorizza un riferimento a un nodo fiber, consentendo a React di determinare rapidamente quale Provider corrisponde a quel contesto. Quando un Provider aggiorna il suo valore, React segna tutti i nodi fiber che utilizzano quel contesto per la rirenderizzazione.

Provider e contesti annidati

I componenti Provider possono essere annidati l'uno dentro l'altro, creando una gerarchia di contesti. Ogni Provider figlio sovrascrive il valore del genitore per il proprio sottoalbero. Questo è utile quando uno schermo necessita di un tema chiaro mentre una finestra modale annidata necessita di un tema scuro. useContext restituisce sempre il valore del Provider più vicino verso l'alto nell'albero.

jsx
const UserContext = createContext(null);
const ThemeContext = createContext('chiaro');

function App() {
    return (
        <UserContext.Provider value={{ name: 'Alice' }}>
            <ThemeContext.Provider value='dark'>
                <Profile />
            </ThemeContext.Provider>
        </UserContext.Provider>
    );
}

Creazione di un provider con createContext

La funzione createContext(defaultValue) crea un oggetto contesto. Il parametro defaultValue viene utilizzato quando un componente chiama useContext ma non c'è un Provider corrispondente sopra nell'albero. Senza defaultValue, useContext restituirà undefined, il che può portare a errori imprevisti. Si raccomanda di passare sempre un valore predefinito significativo o null.

Creare un provider personalizzato è un pattern comune per incapsulare la logica del contesto. All'interno di tale provider, lo stato viene memorizzato (tramite useState o useReducer) e fornito attraverso la prop value del Provider. Questo nasconde i dettagli implementativi ai componenti consumatori e centralizza la logica di gestione del contesto in un unico punto.

jsx
// Provider personalizzato con gestione dello stato
const AuthContext = createContext(null);

function AuthProvider({ children }) {
    const [user, setUser] = useState(null);

    const login = useCallback(async (email, pass) => {
        const u = await loginApi(email, pass);
        setUser(u);
    }, []);

    return (
        <AuthContext.Provider value={{ user, login }}>
            {children}
        </AuthContext.Provider>
    );
}

Utilizzo di useContext nei componenti figli

Nei componenti funzionali, useContext è l'unico modo per accedere al contesto. Sostituisce il componente Consumer della vecchia Context API, che richiedeva il pattern render-prop: <ThemeContext.Consumer>{value => ...}</ThemeContext.Consumer>. useContext rende il codice più lineare e leggibile, specialmente quando si lavora con più contesti in un unico componente.

Quando si utilizzano più contesti in un componente, è sufficiente chiamare useContext più volte per ogni contesto. Ogni chiamata restituisce il valore del Provider corrispondente. L'ordine delle chiamate non è importante, poiché ogni contesto è un'entità indipendente. React ottimizza le chiamate multiple attraverso lo stesso sistema di riferimenti fiber.

jsx
function Dashboard() {
    const { user } = useContext(AuthContext);
    const theme = useContext(ThemeContext);
    const { locale } = useContext(I18nContext);

    return (
        <div className={`dashboard-${theme}`}>
            <h1>{locale.greeting}, {user.name}</h1>
        </div>
    );
}

useContext vs Redux: quando scegliere cosa

La scelta tra useContext e Redux dipende dalla scala e dalla complessità della gestione dello stato. useContext + useReducer è un sostituto leggero di Redux per applicazioni piccole e medie. Non richiede l'installazione di una libreria esterna, è più facile da imparare ed è sufficiente per la maggior parte dei compiti. Redux è giustificato quando è necessaria un'architettura rigorosa con middleware, strumenti di sviluppo e aggiornamenti immutabili.

Il principale vantaggio di Redux rispetto a useContext è l'ottimizzazione della rirenderizzazione. Per impostazione predefinita, quando il valore in un Provider cambia, tutti i consumatori del contesto vengono rirenderizzati. Redux con useSelector e shallowEqual permette ai componenti di iscriversi solo a parti specifiche dello stato, il che riduce significativamente il numero di rirenderizzazioni nelle applicazioni grandi. Il contesto può anche essere ottimizzato suddividendolo in molti piccoli contesti.

CriteriouseContextRedux
ComplessitàNessuna dipendenza esternaRichiede configurazione di store e middleware
RirenderizzazioniTutti i consumatori a ogni modificaSolo quelli iscritti a uno slice specifico
DevToolsReact DevToolsRedux DevTools con viaggio nel tempo
MiddlewareNon supportatoRedux Thunk, Saga, Observable
Quando scegliereApp medie, 3–5 contestiApp grandi con logica di business complessa

Secondo i Manutentori di Redux — Quando usare Redux (2024), il 70% delle applicazioni React non ha bisogno di Redux. Se hai meno di 50 componenti e lo stato non coinvolge logica complessa con caching, debounce ed effetti collaterali — useContext + useReducer è più che sufficiente. Redux aggiunge codice boilerplate e dovrebbe essere usato consapevolmente.

Errori tipici con useContext

L'errore più comune è ricreare l'oggetto value a ogni renderizzazione del Provider. Se passi value={{ user, login }} al Provider, viene creato un nuovo oggetto a ogni renderizzazione del Provider, causando la rirenderizzazione di tutti i consumatori anche se i dati non sono cambiati. La soluzione è memoizzare il valore con useMemo o utilizzare contesti separati per dati che cambiano frequentemente e raramente.

  • Rirenderizzazioni inutili — un nuovo oggetto value a ogni renderizzazione del Provider. Usa useMemo per memoizzare il valore.
  • Contesto troppo grande — un unico Provider con decine di campi costringe tutti i componenti figli a rirenderizzarsi quando qualsiasi campo cambia. Dividi in più contesti per significato.
  • Mancanza di defaultValue — se non viene trovato alcun Provider, useContext restituisce defaultValue, e se è undefined, ogni chiamata lancerà un TypeError.
  • Provider annidati dello stesso tipo — sovrascrivere il contesto a livelli profondi può creare confusione e portare a valori inaspettati.
jsx
// ❌ Nuovo oggetto a ogni renderizzazione — tutti i consumatori si rirenderizzano
<AuthContext.Provider value={{ user, login }}>{children}</AuthContext.Provider>

// ✅ Valore memoizzato — rirenderizzazione solo quando user o login cambia
const authValue = useMemo(() => ({ user, login }), [user, login]);
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>

Per risolvere il problema del “contesto grande”, dividi lo stato globale in gruppi logici: AuthContext, ThemeContext, I18nContext. Ogni contesto è responsabile della propria area e si aggiorna indipendentemente. Questo è più semplice che cercare di ottimizzare un contesto gigante tramite useMemo e offre un comportamento di rirenderizzazione più prevedibile.

Domande frequenti

Si può modificare il contesto da un componente figlio?

Sì, se si passa una funzione mutatrice nel value del Provider. Il pattern tipico è memorizzare lo stato nel Provider e passare sia i dati che le funzioni di aggiornamento tramite useContext. I componenti figli chiamano queste funzioni e il cambiamento di stato nel Provider aggiorna automaticamente tutti i consumatori. Questo è un sostituto base di Redux per applicazioni piccole.

Cosa è più veloce — useContext o Redux?

Per scenari semplici, useContext è più veloce a causa dell'assenza dell'overhead dello store e del middleware. Ma con aggiornamenti frequenti e molti consumatori, Redux vince perché i suoi selettori (useSelector) si iscrivono solo a parti specifiche dello stato, mentre useContext rirenderizza tutti i consumatori a ogni modifica. Per applicazioni con alta frequenza di aggiornamenti (animazioni, tempo reale), scegli Redux o librerie specializzate.

Si può usare useContext al di fuori di un componente React?

No. useContext, come tutti gli hook, può essere chiamato solo all'interno di un componente funzionale React o di un hook personalizzato. Se hai bisogno di ottenere il valore del contesto in una funzione normale (ad esempio, in un'utilità o servizio), passalo come parametro dal componente o usa un modulo separato con stato globale al di fuori di React.

Come funziona useContext con TypeScript?

La tipizzazione del contesto in TypeScript si effettua specificando il tipo in createContext: createContext<AuthContextType | null>(null). Questo garantisce che useContext(AuthContext) restituisca un valore del tipo corretto. Un pattern conveniente è creare un hook personalizzato useAuth che chiama useContext, controlla se è null e lancia un errore chiaro: “useAuth deve essere usato all'interno di AuthProvider”.

Perché useContext restituisce undefined quando esiste un Provider?

La ragione più comune è che il componente consumatore non si trova all'interno del Provider corrispondente. Verifica che il Provider avvolga l'intero sottoalbero in cui viene usato useContext. La seconda ragione — al Provider è stato passato un oggetto contesto diverso: lo sviluppatore crea un contesto con createContext ma usa useContext con un'istanza diversa di createContext.

Riepilogo

  • useContext — hook per leggere un valore dal contesto React, eliminando la necessità di props drilling.
  • createContext — crea un oggetto contesto con un Provider per trasmettere dati e un defaultValue per i casi senza Provider.
  • Memoizzare il valore — usa useMemo per il valore del Provider per evitare rirenderizzazioni inutili dei consumatori.
  • Dividere i contesti — dividi lo stato globale in più piccoli contesti per gruppi logici.
  • Gerarchia dei Provider — è possibile annidare Provider dello stesso tipo per sovrascrivere valori in una parte dell'albero.
  • useContext + useReducer — un sostituto leggero di Redux per app medie senza dipendenze esterne.
  • Non sostituisce Redux — per logica complessa con middleware e aggiornamenti frequenti, scegli Redux con selettori.

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