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 è 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.
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>;
}
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.
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.
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>
);
}
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.
// 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>
);
}
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.
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>
);
}
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.
| Criterio | useContext | Redux |
|---|---|---|
| Complessità | Nessuna dipendenza esterna | Richiede configurazione di store e middleware |
| Rirenderizzazioni | Tutti i consumatori a ogni modifica | Solo quelli iscritti a uno slice specifico |
| DevTools | React DevTools | Redux DevTools con viaggio nel tempo |
| Middleware | Non supportato | Redux Thunk, Saga, Observable |
| Quando scegliere | App medie, 3–5 contesti | App 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.
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.
// ❌ 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
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.
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.
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.
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”.
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
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.
Leggi anche