<StrictMode> è un componente React che attiva controlli aggiuntivi per tutto ciò che contiene, solo in sviluppo. Renderizza ogni componente due volte, esegue al montaggio il setup, la funzione di cleanup e di nuovo il setup di ogni effetto, esegue i ref callback due volte, e avvisa delle API deprecate. È per questo che in sviluppo useEffect "viene eseguito due volte". In una build di produzione non fa nulla.
Lo attivi racchiudendo la tua app, di solito in main.jsx:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
);
Le anteprime di questa pagina girano come una build di produzione, quindi lì StrictMode non avrebbe alcun effetto visibile. Invece, ogni esempio qui sotto contiene il tipo di bug che StrictMode esiste per intercettare, e ti permette di attivarlo a mano. Qui un effetto aggiunge un listener per i clic su document e non lo rimuove mai. Nascondi e mostra il pannello un paio di volte, poi clicca sulla pagina.
Ogni Show aggiunge un altro listener, e nessuno viene rimosso, quindi un singolo clic registra una riga per ogni montaggio. È una perdita che un utente potrebbe causare aprendo e chiudendo un pannello. StrictMode la mostrerebbe al primissimo montaggio: in sviluppo monta, smonta e monta di nuovo, quindi vedresti due righe di log per clic prima ancora di toccare il pulsante.
Effetti: setup, cleanup, setup
Al montaggio, StrictMode esegue il tuo effetto, poi la sua funzione di cleanup, poi di nuovo l'effetto. Simula ciò che succede quando un utente lascia una schermata e ci ritorna, e verifica che la tua funzione di cleanup annulli il tuo setup. Se lo fa, il secondo setup lascia le cose esattamente come le lascerebbe un solo setup, e non vedi nulla di sbagliato. Se non lo fa, il bug compare subito.
La soluzione per il logger è una funzione di cleanup che rimuove la stessa funzione che ha aggiunto:
Cambia tutte le volte che vuoi: ogni clic registra una riga mentre il logger è visibile. Con StrictMode in sviluppo la console inizierebbe con setup, cleanup, setup, e l'app si comporterebbe comunque correttamente. Quella sequenza è il segno di un effetto sano, non un problema da spegnere.
Effetti comuni che hanno bisogno di una funzione di cleanup: event listener, setInterval e setTimeout, sottoscrizioni, connessioni WebSocket o di chat, e richieste la cui risposta va ignorata se il componente non c'è più. La pagina su useEffect mostra lo schema di cleanup per ciascuno.
Rendering: chiamati due volte
StrictMode chiama anche la funzione del tuo componente due volte per ogni rendering (e le funzioni che passi a useState, useMemo e useReducer, e il constructor, render e shouldComponentUpdate delle classi). React tiene il risultato di una chiamata e butta via l'altro. Un componente puro restituisce lo stesso JSX entrambe le volte, quindi non cambia nulla.
Un componente che cambia qualcosa al di fuori di sé durante il rendering non è puro, e chiamarlo due volte fa avvenire il cambiamento due volte. Questo aggiunge una voce "rendered at" a un array che riceve come prop:
Ogni nuovo render aggiunge una voce che nessuno ha chiesto. Qui te ne accorgi solo dopo aver cliccato. Con StrictMode già il primo rendering mostrerebbe due voci nuove invece di una. La soluzione è calcolare durante il rendering senza modificare nulla: const shown = [...entries, 'extra'].
React 19 aggiunge un dettaglio: durante il doppio rendering, useMemo e useCallback riutilizzano il risultato della prima chiamata invece di calcolarlo due volte.
Ref callback
Da React 19, StrictMode esegue due volte al montaggio anche i ref callback: collegamento, cleanup, collegamento. Un ref callback che aggiunge un listener o registra il nodo da qualche parte deve restituire una funzione di cleanup, esattamente come un effetto:
<div
ref={(node) => {
const observer = new ResizeObserver(onResize);
observer.observe(node);
return () => observer.disconnect();
}}
/>
Avvisi sulle API deprecate
StrictMode avvisa delle API in via di dismissione, per lo più nei class component, come i vecchi metodi del ciclo di vita UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps e UNSAFE_componentWillUpdate. Alcune API di cui avvisava in passato, come i ref stringa e findDOMNode, sono state rimosse del tutto da React 19.
Attivarlo per una parte dell'app
<StrictMode> è un componente normale, quindi puoi racchiudere solo una parte dell'albero. Questo aiuta quando lo adotti in un'app grande: inizia con le schermate nuove ed espandi.
function App() {
return (
<>
<Header />
<StrictMode>
<Sidebar />
<Content />
</StrictMode>
<Footer />
</>
);
}
Sidebar e Content (e tutto ciò che renderizzano) ricevono i controlli; Header e Footer no. Non c'è modo di spegnerlo per un sottoalbero dentro una parte in modalità strict.
Dove è attivo per default:
- Vite: il template React racchiude
<App />in<StrictMode>inmain.jsx. - Next.js: l'App Router lo attiva per default; lo controlla
reactStrictModeinnext.config.js.
In produzione non fa nulla
Una build di produzione ignora <StrictMode>: un rendering, un'esecuzione dell'effetto, nessun avviso. Quindi le doppie chiamate non costano mai nulla ai tuoi utenti, e non c'è motivo di togliere il wrapper prima del deploy.
Se in sviluppo un doppio effetto rompe qualcosa, come una richiesta inviata due volte o un evento di analytics registrato due volte, è un'informazione. La maggior parte delle volte la soluzione è una funzione di cleanup (un flag ignore per una richiesta, una disconnessione per una connessione). Per qualcosa che deve davvero avvenire una volta per caricamento dell'app, come inizializzare un SDK, eseguilo fuori da qualsiasi componente a livello di modulo, oppure proteggilo con un flag a livello di modulo.
let didInit = false;
function App() {
useEffect(() => {
if (didInit) return;
didInit = true;
initAnalytics(); // runs once per page load, even in StrictMode
}, []);
}
Evita il diffuso espediente di un ref che salta la seconda esecuzione dell'effetto. Nasconde l'avviso senza sistemare la funzione di cleanup mancante, e il bug ritorna la prima volta che il componente viene davvero smontato e montato di nuovo, come fa il logger qui sopra.
Domande frequenti
Cosa fa React StrictMode?
Solo in sviluppo, renderizza due volte ogni componente al suo interno, esegue il setup, la funzione di cleanup e di nuovo il setup di ogni effetto quando il componente viene montato, esegue i ref callback due volte allo stesso modo, e avvisa delle API deprecate. Le chiamate in più fanno emergere i rendering non puri e gli effetti senza funzione di cleanup.
Perché il mio useEffect viene eseguito due volte?
Perché il componente sta dentro <StrictMode> e stai eseguendo una build di sviluppo. React lo monta, simula uno smontaggio (viene eseguita la tua funzione di cleanup) e lo monta di nuovo. Se il secondo setup causa un bug, all'effetto manca una funzione di cleanup.
StrictMode ha effetto in produzione?
No. Una build di produzione renderizza una volta ed esegue ogni effetto una volta, con o senza <StrictMode>. Puoi lasciarlo nel tuo codice.
Come disattivo StrictMode?
Togli il wrapper <StrictMode>, di solito in main.jsx o index.js, oppure imposta reactStrictMode: false in next.config.js. Di solito è meglio sistemare la funzione di cleanup: la doppia esecuzione indica un bug in cui possono imbattersi gli utenti reali.
Perché console.log viene stampato due volte?
StrictMode chiama la funzione del tuo componente due volte per ogni rendering in sviluppo. React DevTools può attenuare i log della seconda chiamata, o nasconderli, nelle sue impostazioni.