La tua app React era veloce quando l'hai creata. Ora è lenta, i tempi di caricamento sono aumentati e gli utenti iniziano a accorgersene. La buona notizia è che la maggior parte dei problemi di prestazioni di React deriva da una manciata di cause alla radice risolvibili.
Questa guida illustra sette tecniche collaudate per velocizza la tua app React con dati concreti, modelli di codice pratici e indicazioni chiare su quando applicare ciascuno di essi. Che la tua app sia lenta al primo avvio, tardasse a rispondere agli input dell’utente o abbia difficoltà a gestire grandi set di dati, qui troverai una soluzione mirata.
Prima di scrivere anche solo una riga di codice, apri il Profiler di React DevTools e registra un’interazione che ti sembra lenta. La vista “flamegraph” ti mostra esattamente quali componenti vengono renderizzati, quanto tempo richiede il rendering di ciascuno e cosa lo ha attivato. Ottimizzare senza questi dati significa agire alla cieca. Con questi dati, puoi concentrare i tuoi sforzi dove conta davvero.
1. Suddivisione del codice per un caricamento più veloce
Per impostazione predefinita, lo strumento di compilazione raggruppa l'intera applicazione React in un unico file JavaScript. Ogni utente scarica l'intera applicazione, comprese le parti che non visiterà mai.
Il code splitting suddivide quel pacchetto in parti più piccole che vengono caricate solo quando necessario. React.lazy() insieme a Suspense semplifica la suddivisione a livello di percorso:
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
);
}Il Pannello di controllo Il componente ora viene caricato solo al momento del rendering, non alla prima visita alla pagina. Per la maggior parte delle app, la suddivisione del codice a livello di route riduce le dimensioni iniziali del bundle di 30–50%, migliorando direttamente il Largest Contentful Paint (LCP). Secondo l’HTTP Archive (dati del 2024), la dimensione mediana del payload JavaScript per gli utenti desktop supera già i 500 KB. Una suddivisione massiccia impedisce che tale cifra continui a crescere.
Oltre ai percorsi, valuta la possibilità di separare le librerie di terze parti più pesanti (librerie di grafici, editor di testo formattato, visualizzatori di PDF) che compaiono solo su pagine specifiche. Utilizza Webpack Bundle Analyzer per visualizzare il tuo bundle e individuare i componenti che incidono maggiormente prima di decidere dove effettuare la suddivisione.
2. Memorizzazione per evitare rendering superflui
React esegue il re-rendering di un componente ogni volta che il suo componente padre viene re-renderizzato, anche se le proprietà di quel componente non sono cambiate. In una dashboard con 50 componenti, una modifica dello stato al livello superiore può far sì che tutti e 50 vengano re-renderizzati inutilmente. Secondo una ricerca condotta da Bit.dev, prestazioni di rendering scadenti possono aumentare il tempo di esecuzione degli script di 30–60%, un duro colpo per entrambi esperienza utente e SEO.
React.memo è la tua prima linea di difesa. Avvolge un componente ed esegue un confronto superficiale delle proprietà prima di procedere al re-rendering:
const ExpensiveList = React.memo(function ExpensiveList({ items }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
});React.memo funziona solo quando i prop che riceve hanno riferimenti stabili. Abbinalo a useMemo per i valori calcolati e useCallback per i gestori di eventi:
function ProductPage({ products }) {
const sortedProducts = useMemo(() => {
return [...products].sort((a, b) => b.price - a.price);
}, [products]);
const handleDelete = useCallback((id) => {
// delete logic
}, []);
return <ExpensiveList items={sortedProducts} onDelete={handleDelete} />;
}Quando non ricorrere alla memorizzazione: Ogni React.memo Il wrapper aggiunge un controllo di confronto superficiale ad ogni renderizzazione. Per i componenti piccoli e veloci da renderizzare, tale sovraccarico può comportare un costo maggiore rispetto alla semplice ri-renderizzazione. Effettua prima un’analisi delle prestazioni con React DevTools, quindi applica la memoizzazione in modo selettivo ai componenti con tempi di renderizzazione superiori a 5–10 ms che vengono attivati frequentemente. Avvolgi tutto in React.memo L'assenza di misurazioni è un anti-pattern comune.
Se applicata correttamente, la memoizzazione può ridurre il numero di nuovi rendering di 30–50% su elenchi di grandi dimensioni. Una verifica interna ha documentato un 40% riduzione del numero di ricalcoli nella pagina di scheda prodotto a seguito di una memoizzazione mirata.
3. Virtualizzare elenchi di grandi dimensioni
Il rendering di un elenco di 500 elementi comporta la creazione da parte del browser di 500 nodi DOM, la gestione di 500 listener di eventi e l'esecuzione di operazioni di layout e paint per tutti questi elementi, anche per quelli che si trovano ben al di fuori dell'area visibile. Il risultato è un rendering iniziale lento, uno scorrimento poco fluido e un elevato utilizzo di memoria.
La virtualizzazione risolve questo problema visualizzando solo gli elementi attualmente visibili nell'area di visualizzazione, oltre a un piccolo buffer. react-window è la libreria più diffusa per questo scopo:
import { FixedSizeList } from 'react-window';
function VirtualizedList({ items }) {
return (
<FixedSizeList
height={400}
itemCount={items.length}
itemSize={50}
width={300}
>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
}Per un elenco di 10.000 elementi, questa modifica rende circa 20 nodi DOM in un dato momento invece di 10.000. È stato documentato che questa singola modifica riduce il tempo di rendering dell'elenco da oltre 3 secondi a un tempo quasi istantaneo.
Utilizza la virtualizzazione quando la tua lista supera i 100 elementi. Al di sotto di tale numero, il DOM gestisce il carico senza un degrado percepibile. Al di sopra di esso, i vantaggi aumentano man mano che l’elenco cresce. Inoltre, assicurati di utilizzare proprietà chiave stabili e univoche: l’uso dell’indice dell’array come chiave causa bug impercettibili durante il riordino e il filtraggio e costringe React a eseguire inutilmente il re-rendering dell’intero elenco.
4. Ottimizzare le immagini e le altre risorse
Le immagini sono in genere i file più pesanti in una pagina React. Le immagini di grandi dimensioni e non compresse rallentano il caricamento della pagina, aumentano i tempi di LCP e consumano inutilmente larghezza di banda, soprattutto sulle reti mobili.
Passa a formati moderni. Le immagini WebP sono dal 25 al 35% più piccolo rispetto ai file JPEG a parità di qualità. Il formato AVIF offre una compressione ancora maggiore laddove il browser lo supporti. Aggiornare la propria pipeline di immagini per fornire WebP come impostazione predefinita è una delle soluzioni più rapide disponibili:
<img src="photo.webp" alt="Product image" />Caricamento differito delle immagini fuori dallo schermo. Il nativo loading="lazy" L'attributo indica al browser di caricare le immagini solo quando entrano nell'area visibile dello schermo. Ciò riduce il peso iniziale della pagina ed evita che le immagini fuori dallo schermo entrino in competizione con le risorse essenziali:
<img src="photo.webp" loading="lazy" alt="Product image" />Fornisci immagini responsive. Inviare un’immagine da 2000 px a uno schermo mobile da 400 px comporta uno spreco di larghezza di banda e rallenta il caricamento. Utilizza srcSet e taglie per visualizzare immagini di dimensioni adeguate in base alla finestra di visualizzazione:
<img
srcSet="photo-400.webp 400w, photo-800.webp 800w"
sizes="(max-width: 600px) 400px, 800px"
src="photo-800.webp"
alt="Product image"
/>Se sei sviluppo con Next.js, il successivo/immagine Il componente gestisce automaticamente la conversione del formato, il ridimensionamento reattivo e il caricamento differito.
5. Utilizzare una build di produzione e ridurre le dimensioni del bundle
Le build di sviluppo di React includono avvisi aggiuntivi, strumenti di debug e codice non minificato, elementi che non devono essere presenti in produzione. Effettuare sempre la distribuzione utilizzando una build di produzione. In Crea un'app React, il che significa correre npm run build. In Next.js, ciò significa prossima versione. La differenza nelle dimensioni dei pacchetti è notevole.
Oltre alla modalità di compilazione, è possibile tenere sotto controllo le dimensioni del bundle grazie al “tree shaking”. I moderni strumenti di bundling (Webpack, Vite, Rollup) eliminano automaticamente il codice inutilizzato, ma solo se si importano esattamente gli elementi necessari:
// Imports the entire lodash library (~70KB)
import _ from 'lodash';
// Imports only the function you need (~2KB)
import debounce from 'lodash/debounce';Quella singola modifica all’importazione riduce il peso di una dipendenza da 70 KB a 2 KB. Se si applica lo stesso principio a 10–15 dipendenze, la riduzione complessiva risulta significativa.
Utilizzo Webpack Bundle Analyzer per individuare i componenti più ingombranti. Spesso ti accorgerai che uno o due pacchetti occupano una quota sproporzionata del tuo bundle e che esistono alternative più leggere.
6. Implementare il caricamento differito dei componenti
Il caricamento differito è strettamente correlato alla suddivisione del codice, ma va oltre i percorsi. Qualsiasi componente il cui rendering sia dispendioso e che non sia necessario al caricamento iniziale è un candidato per il caricamento differito.
L'hai già visto React.lazy() Nella sezione dedicata alla suddivisione del codice. Applicare lo stesso schema a:
- Finestre di dialogo modali che compaiono solo a seguito di un'azione dell'utente
- Pannelli di amministrazione o le schermate delle impostazioni che vengono consultate raramente
- Grafici e visualizzazioni dei dati che si caricano solo su determinate pagine
- Integrazioni con servizi di terze parti — lettori video, visualizzatori di PDF, mappe
Evita di applicare il caricamento differito ai componenti che compaiono immediatamente nella parte visibile della pagina. Se l'utente li vede al primo rendering, devono caricarsi immediatamente; altrimenti, si crea un ritardo visibile che sembra un bug.
Per i campi di ricerca e altre interazioni che richiedono elaborazioni complesse, è consigliabile ricorrere al debouncing per limitare la frequenza con cui tali elaborazioni vengono eseguite:
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedQuery(query);
}, 300);
return () => clearTimeout(timer);
}, [query]);Una finestra di debounce di 300 ms intercetta la maggior parte delle pause durante la digitazione senza aggiungere ritardi percettibili. Per le applicazioni React che utilizzano React 18 o versioni successive, useTransition Offre un'alternativa a React Native che mantiene reattiva l'interfaccia utente rimandando gli aggiornamenti di stato non urgenti, soluzione particolarmente efficace per i modelli di ricerca in tempo reale.
7. Monitorare e analizzare costantemente le prestazioni
La gestione delle prestazioni non è un’attività da svolgere una volta sola. Le funzionalità vengono rilasciate, le dipendenze si accumulano e ciò che oggi è veloce può diventare un collo di bottiglia nel giro di tre mesi. Il monitoraggio continuo è ciò che distingue i team che mantengono le prestazioni ottimali da quelli che riscoprono i problemi solo dopo che gli utenti si sono lamentati.
Ecco gli strumenti da integrare nel tuo flusso di lavoro abituale:
Profiler di React DevTools identifica quali componenti sono stati renderizzati, quanto tempo ha richiesto ciascun rendering e cosa lo ha attivato. Utilizzalo durante lo sviluppo e dopo il rilascio di nuove funzionalità importanti per individuare eventuali regressioni prima che raggiungano l'ambiente di produzione.
Faro (disponibile in Chrome DevTools) verifica la conformità della tua app alle soglie dei Core Web Vitals: LCP inferiore a 2,5 secondi, INP inferiore a 200 millisecondi e CLS inferiore a 0,1. Eseguilo nella tua pipeline di CI per evitare che eventuali regressioni delle prestazioni raggiungano l’ambiente di produzione senza essere rilevate.
Web Vitals JS raccoglie dati reali degli utenti in ambiente di produzione. Le misurazioni effettuate in laboratorio non sempre rispecchiano l'esperienza effettiva degli utenti su diversi dispositivi e in diverse condizioni di rete. I dati raccolti sul campo, invece, sì.
Scheda "Prestazioni" di Chrome DevTools fornisce una visione fotogramma per fotogramma dei tempi di esecuzione di JavaScript, delle operazioni lunghe, degli eventi di paint e layout e dei frame drop. Utilizzalo quando il Profiler rileva un componente lento, ma hai bisogno di capire cosa sta succedendo a livello di browser.
Integra l'analisi delle prestazioni nel processo di revisione del codice, in particolare per i componenti condivisi e i kit UI. Esamina i flamegraph dopo ogni rifattorizzazione significativa. Imposta avvisi per le regressioni dei Core Web Vitals. I team che individuano per primi i problemi di prestazioni impiegano meno tempo a risolverli.
Un'app React più veloce inizia con l'approccio giusto
La velocità non è solo un parametro tecnico. Ogni 100 millisecondi di latenza ha un impatto misurabile sui tassi di conversione, e i siti che superano tutte e tre le soglie dei Core Web Vitals ottengono costantemente risultati migliori rispetto alla concorrenza nella ricerca organica.
Le tecniche illustrate in questa guida — suddivisione del codice, memoizzazione, virtualizzazione, ottimizzazione delle immagini, build di produzione, caricamento differito e monitoraggio continuo — affrontano le cause alla radice della maggior parte dei problemi di prestazioni di React. Applicatele in modo sistematico, misurate le prestazioni prima e dopo ogni modifica e concentrate i vostri sforzi sui colli di bottiglia effettivamente individuati dal Profiler.
Sei pronto a migliorare ulteriormente le prestazioni di React?
Monarch Innovation collabora con i team di sviluppo per individuare i colli di bottiglia nelle prestazioni, implementare strategie di ottimizzazione e realizzare applicazioni React più veloci e scalabili. Scopri cosa può fare Monarch Innovation per il tuo progetto.
Domande frequenti
Che cos’è il code splitting e in che modo accelera un’applicazione React?
Il code splitting è una tecnica che suddivide l'applicazione React in bundle JavaScript più piccoli, anziché caricare l'intera applicazione in una sola volta. Ciò consente agli utenti di scaricare solo il codice necessario per la pagina corrente, riducendo il tempo di caricamento iniziale e migliorando le prestazioni. React supporta il code splitting tramite React.lazy() e dinamico import().
Quando dovrei usare React.memo, useMemo e useCallback?
Questi strumenti di ottimizzazione di React aiutano a evitare re-render superflui:
- React.memo: Incornicia i componenti funzionali che ricevono spesso gli stessi prop per evitare un re-rendering superfluo.
- useMemo: Memorizza i calcoli più onerosi in modo che vengano eseguiti solo quando cambiano le dipendenze.
- useCallback: Memorizzare le funzioni di callback per evitare la ricreazione superflua delle funzioni, soprattutto quando si passano funzioni ai componenti figli.
Utilizzale solo quando l'analisi delle prestazioni evidenzia dei colli di bottiglia, poiché un uso eccessivo della memoizzazione può aggiungere una complessità superflua.
Come si fa a virtualizzare elenchi di grandi dimensioni in React?
La virtualizzazione esegue il rendering solo degli elementi visibili in un elenco lungo, anziché di tutti gli elementi presenti nel DOM. Ciò migliora notevolmente le prestazioni di rendering e riduce l'utilizzo della memoria. Librerie come react-window e react-virtualized sono comunemente utilizzati per visualizzare in modo efficiente migliaia di righe, garantendo al contempo uno scorrimento fluido.
Come posso ottimizzare le immagini in un'app React?
L'ottimizzazione delle immagini migliora la velocità della pagina e l'esperienza dell'utente:
- Compressione delle immagini prima della distribuzione.
- Utilizzando formati moderni come WebP oppure AVIF.
- Fornire immagini responsive con dimensioni adeguate.
- Implementazione del caricamento differito per le immagini situate sotto la linea di scorrimento.
- Utilizzo di una CDN per una distribuzione più veloce delle immagini.
Queste pratiche riducono l'utilizzo della larghezza di banda e migliorano i Core Web Vitals.
Che cos’è il lazy loading e quali componenti dovrei caricare in modo differito in React?
Il caricamento differito ritarda il caricamento dei componenti fino al momento in cui sono effettivamente necessari. Riduce le dimensioni iniziali del pacchetto e accelera il caricamento della prima pagina.
Tra i candidati ideali per il caricamento differito figurano:
- Pagine basate sui percorsi
- Pannelli di controllo amministrativi
- Pagine delle impostazioni
- Grafici e moduli di analisi
- Formulari di grandi dimensioni
- Finestre modali e finestre di dialogo
- Componenti di terze parti che non sono immediatamente visibili
React offre React.lazy() e Suspense per implementare il caricamento differito in modo efficiente.
Come posso monitorare costantemente le prestazioni di un'applicazione React?
Il monitoraggio delle prestazioni dovrebbe essere un processo continuo. Tieni sotto controllo regolarmente metriche quali il tempo di caricamento delle pagine, la reattività alle interazioni, la dimensione dei bundle e i Core Web Vitals. Utilizza strumenti come Lighthouse, React DevTools Profiler, il pannello “Performance” di Chrome DevTools e soluzioni di Real User Monitoring (RUM) per individuare eventuali colli di bottiglia. Il monitoraggio continuo aiuta a individuare tempestivamente eventuali regressioni e garantisce che la vostra applicazione React rimanga veloce man mano che si evolve.




