Web Design and Engineering

Il React Compiler è qui: c'è ancora qualcosa da memoizzare a mano

React Compiler 1.0 è stabile da ottobre 2025. Ecco dove useMemo, useCallback e React.memo servono ancora e dove il compilatore li sostituisce.

23 aprile 20267 min di lettura
Il React Compiler è qui: c'è ancora qualcosa da memoizzare a mano

Hai aggiunto useMemo per fermare un filtro su una lista. Hai avvolto ogni handler in useCallback così un figlio memoizzato smetteva di re-renderizzare. Hai promosso metà dell'albero a React.memo quando il profiler dava numeri sbagliati. Ha funzionato. Ha anche raddoppiato il carico cognitivo di ogni componente e reso i refactor dolorosi.

React Compiler 1.0 è uscito il 7 ottobre 2025, dopo due anni di release candidate e deploy in produzione dentro Meta. Prende in carico gran parte di quel lavoro in modo automatico. La domanda non è più se adottarlo ma quali delle tue chiamate manuali di memoizzazione hanno ancora un motivo di esistere. Ecco come ragioniamo in Studio quando prendiamo in mano una codebase React.

Cosa fa davvero il compiler

React Compiler è un compilatore ottimizzante per React che gira a build time. Legge i componenti e gli hook, capisce il flusso dei dati e la mutabilità, e inserisce memoizzazione in automatico. Può memoizzare valori singoli dentro un componente, memoizzare attraverso rami condizionali, e saltare il re-render di un sottoalbero quando gli input a quel sottoalbero sono stabili. Non lo importi a runtime. Lo aggiungi alla pipeline di build e riscrive il codice che spedisce.

È compatibile con React 17, 18 e 19. Su React 17 e 18 si aggiunge il pacchetto react-compiler-runtime; su React 19 funziona nativamente. In Next.js si attiva da experimental.reactCompiler in next.config.js. Expo, Remix, Vite e Metro hanno tutti configurazioni supportate.

In una codebase che il compiler riesce a coprire, il risultato netto è che la maggior parte di quello che facevi a mano con useMemo, useCallback e React.memo è ora lavoro del compilatore.

Cosa sostituisce di default

  • useMemo per valori derivati. Filtrare una lista, ordinarla, calcolare totali: il compilatore memoizza queste cose in automatico basandosi sugli input che vede.
  • useCallback per gli handler di eventi. Se un handler viene passato a un figlio, il compilatore stabilizza il suo riferimento così il figlio non re-renderizza.
  • React.memo sulla maggior parte dei componenti. Se le props di un componente sono già stabilizzate a monte, il compilatore salta il re-render di quel componente senza che tu debba avvolgerlo.

Per codice nuovo, la guida ufficiale del team React è scrivere componenti in modo semplice e lasciare la memoizzazione al compilatore. Gli hook manuali restano solo quando serve un controllo preciso.

Dove la memoizzazione manuale ha ancora senso

La documentazione stessa del compiler lascia vivi quattro casi limite, non come residuato ma come bordi taglienti che il compiler sceglie di non smussare.

1. Valori usati come dipendenze di un effetto

Quando un valore è usato dentro l'array di dipendenze di un useEffect, serve un controllo esatto su quando è considerato nuovo. La memoizzazione del compiler è un dettaglio di implementazione: può cambiare con versioni future. Se un effetto deve scattare solo quando una certa derivazione cambia, tieni il useMemo per quella derivazione. La documentazione React lo elenca come motivo di prim'ordine per tenere memoizzazione manuale.

2. Librerie di terze parti che controllano l'uguaglianza per riferimento

Librerie di grafici, di tabelle, di liste virtualizzate: un pezzo importante dell'ecosistema React confronta le props per riferimento, non per valore. Se D3, AG Grid o TanStack Table si aspettano che columns sia lo stesso array tra un render e l'altro, devi comunque garantirlo. La stabilizzazione del compiler è opaca per te, quindi il pattern più sicuro è un useMemo esplicito sul confine dove il tuo codice passa dati alla libreria.

3. Calcoli puri estremamente costosi

Il compiler memoizza in modo aggressivo ma non infinito. Per qualcosa come un calcolo sincrono di layout da 50 ms, vuoi essere esplicito che non deve mai girare due volte con lo stesso input. Avvolgilo in useMemo, scrivi un commento che spiega il costo, e vai avanti. La regola è la stessa di prima del compiler: avvolgi ciò che il profiler prova costoso, non ciò che immagini possa esserlo.

4. React.memo con funzione di confronto personalizzata

Il compiler usa shallow equality di default. Se hai un componente che deve re-renderizzare solo quando cambia un campo specifico dentro un oggetto più grande, React.memo(Component, customCompare) è ancora lo strumento giusto. Il compiler non ti combatte; semplicemente non prova a essere più furbo del tuo confronto personalizzato.

Come decidiamo in Studio

Su una codebase nuova, accendiamo il compiler dal giorno uno, abilitiamo il preset recommended-latest di eslint-plugin-react-hooks, e scriviamo componenti semplici. Aggiungiamo useMemo o useCallback solo quando si applica uno dei quattro casi sopra, e lasciamo un commento breve che dice quale. Quel commento non è decorativo: dice al prossimo lettore perché questo hook specifico è sopravvissuto e non può essere cancellato.

Su una codebase esistente, non strappiamo via la memoizzazione. Il team React lo sconsiglia esplicitamente, perché rimuovere useMemo può cambiare l'output compilato e sorprenderti. Accendiamo il compiler, guardiamo l'output di build, sistemiamo le violazioni delle Rules of React che il layer di validazione del compiler segnala, e lasciamo vivere le vecchie chiamate di memoizzazione. Quando tocchiamo un file per una feature, ripuliamo la memoizzazione di quel file come parte del diff. Non prima.

Le direttive: 'use memo' e 'use no memo'

Il compiler supporta due direttive a livello di funzione per un controllo locale.

'use memo' forza il compiler a ottimizzare una funzione specifica, anche in una codebase in modalità opt-in. Utile quando adotti il compiler prima su un sottoinsieme di componenti.

'use no memo' è l'opposto: dice al compiler di saltare completamente questa funzione. Sia la documentazione React sia gli autori del compiler la inquadrano come una via di fuga temporanea, non una soluzione permanente. Il flusso è: incontri un bug del compiler, aggiungi 'use no memo' con un TODO, apri un'issue, sistemi la violazione sottostante, rimuovi la direttiva.

function Dashboard() {
  'use no memo'
  // TODO(#1234): rimuovere quando sistemiamo la mutation dentro renderRow
  return <Table rows={rows} />
}

Non trattare 'use no memo' come un opt-out di lungo periodo. Se un file ne ha bisogno per mesi, qualcosa in quel file sta violando le Rules of React e il compiler fa bene a tirarsi indietro.

Le regole di lint che prendono il posto della vecchia abitudine

React Compiler 1.0 spedisce con un eslint-plugin-react-hooks espanso. Il preset recommended-latest abilita un insieme più ampio di regole che il compiler deriva dalla sua analisi statica. Quelle che cambiano di più il lavoro quotidiano sono:

  • purity: segnala codice non puro in render, incluse mutation ed effetti collaterali che il compiler rifiuta di memoizzare.
  • refs: segnala letture o scritture di ref durante il render.
  • set-state-in-effect: segnala il classico anti-pattern di chiamare setState dentro un effetto che innesca un loop di render derivati.
  • preserve-manual-memoization: avvisa quando una useMemo manuale viene rimossa in un modo che cambierebbe il comportamento, ed è la regola che ti protegge durante una migrazione incrementale.

Se il tuo team è stato prudente nell'attivare nuove regole ESLint, attiva questa. Si ripaga al primo refactor.

Cosa cambia per i team di prodotto

Il risultato interessante non è che le app vanno più veloci, anche se vanno più veloci. È che il codice dei componenti diventa più corto e più leggibile. Meno hook significano meno array di dipendenze, meno battaglie con exhaustive-deps, e meno regressioni di performance introdotte da uno sviluppatore junior che passa per sbaglio un riferimento instabile.

Sui progetti dove abbiamo migrato, il beneficio più visibile dopo tre mesi è la velocità di onboarding. I nuovi contributor leggono il codice dall'alto in basso invece di decifrare un albero di Natale di wrapper di memoizzazione. Il lavoro di performance che sopravvive è il lavoro che merita di essere scritto a mano: il calcolo costoso, il confine con la libreria, la dipendenza che un certo effetto deve osservare. Tutto il resto è del compilatore.

Foto di Shahabudin Ibragimov su Unsplash

Studio

Inizia un progetto.

Un partner unico per aziende, PA, startup e SaaS. Produzione più veloce, tecnologie moderne, costi ridotti. Un team, una fattura.