React

Profiler: trovare il componente lento

Registra una sessione, ordina per tempo di rendering e leggi il primo componente della classifica. Il Profiler misura React, non layout e paint.

In sintesi

  • Il Profiler misura il tempo di render e commit di React, non il tempo di layout o paint.
  • La build di profilazione di react-dom 18.3.1 pesa 9.427 byte in più della build di produzione.
  • Una sessione con una sola interazione isola il componente; dieci interazioni producono rumore.

Risposta breve: apri React DevTools, registra una sessione con il Profiler, riproduci l'interazione lenta e ordina i componenti per tempo di rendering. Il primo della lista è il candidato, non la prova.

Cosa misura e cosa no

Il Profiler misura il lavoro di React: tempo di render di un sottoalbero, tempo di commit e motivo del nuovo render. Non misura layout, paint né il tempo passato dentro un handler: quelli arrivano dal pannello Performance del browser, e il totale si legge solo lì.

Il wrapper minimo

import { Profiler } from "react";

type Row = { id: string; price: number };

function onRender(
  id: string,
  phase: "mount" | "update" | "nested-update",
  actualDuration: number,
  baseDuration: number,
) {
  if (actualDuration  }) {
  return (
    
      
    
  );
}

La callback onRender arriva solo con la build di profilazione: actualDuration è il tempo speso in quel render, baseDuration quello che servirebbe senza memoizzazione. La distanza fra i due dice se memo e useMemo stanno lavorando o solo aggiungendo codice.

Il giro che serve

  • Una interazione sola: un click, un filtro, un cambio tab. Una sessione con dieci interazioni non isola niente.
  • La classifica, non le barre: la classifica ordina per tempo speso, le barre mostrano la sequenza dei render.
  • Il motivo: apri il componente e leggi perché è tornato a renderizzare, fra props nuove, stato cambiato e context.
  • La ripetizione: rifai la stessa interazione dopo la correzione, altrimenti non hai un confronto.

Senza DevTools

Per una misura ripetibile avvolgi il sottoalbero sospetto in Profiler e registra solo i casi sopra una soglia. In Next.js la build di profilazione si attiva con l'opzione reactProductionProfiling; nei progetti Vite si punta l'alias di react-dom sulla variante profiling.

Il comando

npx react-devtools

Le interfacce da misurare si costruiscono da record esistenti: la libreria shadcn per i primitivi, i blocchi dashboard per una pagina con tabelle e grafici, e progress-indicator come componente piccolo da profilare.

La limitazione

Il Profiler vede solo il lavoro di React: un componente che renderizza in 2 ms ma forza un layout sincrono da 40 ms resta quasi invisibile. Il tempo che l'utente percepisce si legge nel browser e si chiama INP, descritto in INP e reattività.

Dove continuare

Il rendering e il suo costo sono spiegati in che cos'è React; cosa cambia con la versione 19 è in React 19. Per fissare una soglia in CI leggi soglie Lighthouse in CI, e per il confronto fra librerie la classifica misurata.

Domande frequenti

Il Profiler funziona in produzione?

Sì, ma solo con la build di profilazione di react-dom: quella standard non chiama onRender. La build di profilazione pesa 9.427 byte in più nell'installazione locale di react-dom 18.3.1.

Perché actualDuration e baseDuration sono diversi?

actualDuration è il tempo del render appena fatto, baseDuration quello che servirebbe se ogni figlio renderizzasse senza memoizzazione. Se actualDuration resta alto con baseDuration basso, la memoizzazione non sta funzionando.

Devo profilare ogni componente?

No. Avvolgi solo il sottoalbero che sospetti, con un id riconoscibile, e registra i casi sopra una soglia: un wrapper su tutto l'albero produce log che nessuno legge.

Il Profiler trova anche i problemi di layout?

No. Misura render e commit di React, non layout e paint del browser. Per quelli serve il pannello Performance o una misura di INP sul campo.

Posso usare il Profiler in un test?

Sì, avvolgi il componente nel test e raccogli le chiamate di onRender in un array. È utile per verificare che un aggiornamento non faccia renderizzare un ramo che dovrebbe restare fermo.