
React 19: `use` vs `useContext`, cosa cambia e quando preferirlo
La nuova use() di React 19 si sovrappone a useContext ma viola di proposito le Rules of Hooks. Differenze spiegate con esempi su contesto e promise.
React 19 introduce una nuova funzione built-in chiamata use. In superficie sembra un sostituto diretto di useContext — puoi chiamare use(ThemeContext) e ottenere lo stesso valore. Ma use non è un hook, non segue le Rules of Hooks, e fa molto più che leggere il contesto. Se hai già letto la mia guida a useContext, questo è il passo successivo naturale: capire dove si colloca use e quando usarlo porta davvero un vantaggio.
use non è un hook
Ogni hook che conosci — useState, useEffect, useContext — deve essere chiamato incondizionatamente, al livello più alto di un componente, nello stesso ordine ad ogni render. È questa regola che permette a React di tracciare lo stato degli hook in base alla posizione della chiamata. use viola questa regola di proposito: puoi chiamarlo dentro un if, un loop, o dopo un return anticipato.
function Greeting({ showTheme }) {
// Illegale con useContext, perfettamente valido con use()
if (showTheme) {
const theme = use(ThemeContext);
return <h1>Tema: {theme}</h1>;
}
return <h1>Ciao</h1>;
}
React può permetterlo perché use non traccia uno stato tra i render come fa useState — legge un valore che esiste già (un contesto, o il valore risolto di una promise) nel momento in cui viene chiamato. Per questo motivo il team di React ha evitato di chiamarlo useUse o simile: è volutamente esente dalla convenzione di naming use* e dalle sue regole.
ℹ️ Nota
use non può comunque essere chiamato dentro un blocco try/catch, né dentro una funzione
JavaScript qualsiasi che non sia un componente o un custom hook — React deve sapere che sta
girando dentro un render.
Leggere il contesto: use(Context) vs useContext(Context)
Nel caso semplice sono intercambiabili:
// Con useContext
function Toolbar() {
const theme = useContext(ThemeContext);
return <div className={theme}>...</div>;
}
// Con use
function Toolbar() {
const theme = use(ThemeContext);
return <div className={theme}>...</div>;
}
La differenza pratica emerge quando la lettura del contesto è condizionale. Immagina un componente che ha bisogno del valore del contesto solo in un ramo:
function Panel({ isExpanded }) {
// Con useContext devi comunque chiamarlo incondizionatamente,
// anche se usi il valore solo dentro l'if.
const theme = useContext(ThemeContext);
if (!isExpanded) return null;
return <div className={theme}>Contenuto espanso</div>;
}
function Panel({ isExpanded }) {
if (!isExpanded) return null;
// Con use(), leggi il contesto solo quando serve davvero
const theme = use(ThemeContext);
return <div className={theme}>Contenuto espanso</div>;
}
Nella maggior parte dei casi le due versioni si comportano allo stesso modo, perché leggere il contesto è un’operazione economica. Il vero vantaggio non è la performance — è poter scrivere componenti la cui logica segue la struttura reale del codice, invece di dover sempre leggere il contesto incondizionatamente in cima.
Leggere le promise con use() e Suspense
È qui che use fa qualcosa che useContext non è mai stato progettato per fare: può “srotolare” una promise, sospendendo il componente finché non si risolve.
function Comments({ commentsPromise }) {
// `use` sospende questo componente finché la promise non si risolve
const comments = use(commentsPromise);
return (
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.text}</li>
))}
</ul>
);
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<p>Caricamento commenti...</p>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
Mentre commentsPromise è in sospeso, React mostra il fallback del <Suspense> più vicino. Una volta risolta, Comments viene renderizzato con il valore risolto — niente useEffect, niente stato di caricamento gestito a mano, niente flag isPending da mantenere.
⚠ Importante
Non creare la promise dentro il componente in cui chiami use() — creeresti una nuova promise ad
ogni render, innescando un loop infinito di render/sospensione. La promise deve arrivare
dall’esterno del render (un Server Component, una cache, o un riferimento stabile creato una sola
volta) e passata come prop, come commentsPromise nell’esempio sopra.
Se la promise viene rifiutata, il nearest error boundary la intercetta — un pattern che si lega naturalmente a quanto ho scritto nell’articolo sugli error boundary in React.
use vs useContext a colpo d’occhio
useContext |
use |
|
|---|---|---|
| Legge il contesto | Sì | Sì |
| Legge le promise | No | Sì |
| Chiamabile condizionalmente / nei loop | No | Sì |
| Segue le Rules of Hooks | Sì | No (esente di proposito) |
| Disponibile da | React 16.8 | React 19 |
| Chiamabile fuori dai componenti | No | No (serve comunque un contesto di render) |
Quindi quale scegliere?
- Se leggi il contesto incondizionatamente in cima al componente,
useContextva benissimo ed è perfettamente idiomatico — non serve riscrivere codice esistente solo perchéuseesiste. - Passa a
usequando la lettura del contesto è davvero condizionale, o deve stare dentro un loop o dopo un return anticipato. - Passa a
usequando devi srotolare una promise durante il render — tipicamente dati passati giù da un Server Component o unafetchfatta in cache fuori dal componente — e vuoi che Suspense gestisca lo stato di caricamento al posto tuo.
💡 Consiglio
use si integra bene con il pattern in cui un Server Component avvia un fetch di dati, passa giù
la promise non ancora risolta come prop, e un Client Component chiama use() su di essa per
mostrare la UI non appena è pronta — senza bloccare il render iniziale della pagina. Questo
pattern è centrale nei React Server Components, che tratto in un articolo dedicato.
FAQ
❓ Posso sostituire tutti i miei useContext con use?
Sì, dal punto di vista sintattico use(Context) e useContext(Context) restituiscono lo stesso
valore. Ma non c’è nessun vantaggio nel sostituire chiamate già incondizionate in cima al
componente — fallo solo dove ti serve davvero la flessibilità della chiamata condizionale o il
supporto alle promise che use aggiunge.
❓ use() sostituisce useEffect + fetch per il data fetching nei Client Components?
Solo in parte. use() srotola una promise che già hai — non avvia il fetch di per sé. Serve
comunque qualcosa che crei quella promise (un Server Component, un’API di data-loading del
framework, o una cache). Pensa a use come al lato “consumo” dei dati asincroni, non come a una
libreria di fetching.
❓ use() è un Hook di React?
No. React lo documenta intenzionalmente come un’API che “usa” una risorsa, non un hook — per
questo non segue le Rules of Hooks e non compare insieme a useState/useEffect nel riferimento
degli hook.
Conclusione
use e useContext si sovrappongono nella lettura del contesto, ma use è lo strumento più flessibile e generale — chiamate condizionali, loop, supporto alle promise — al costo di essere un’API più nuova e meno collaudata. Tieni useContext per i casi semplici che già hai; passa a use quando la logica del componente ha davvero bisogno di quella flessibilità, o quando stai collegando data fetching basato su Suspense.
Riferimenti

Co-Fondatore & CTO presso PAPION. Senior full-stack engineer specializzato in React, TypeScript, Node.js e sicurezza applicativa.