Cascada de re-renders de React: cuando un clic vuelve a renderizar todo el árbol
Qué ocurre
En React, una actualización de estado vuelve a renderizar el componente y, por defecto, todos sus hijos. Si el estado vive alto en el árbol (un context, un store de nivel de página), una sola pulsación o clic puede volver a renderizar cientos de componentes — la mayoría de los cuales muestran exactamente lo mismo que antes.
Cada render es barato; miles de ellos en un solo manejador no lo son. El trabajo cae en la fase de processing time del INP.
Cómo reconocerlo
- El Profiler de React DevTools muestra flame graphs anchos: los componentes se vuelven a renderizar sin que sus props cambien visiblemente.
- Escribir en un input controlado va a tirones; cada pulsación vuelve a renderizar listas o tablas grandes.
- El processing time domina el INP y la pila en DevTools Performance está llena de internals de React.
Cómo solucionarlo
- Baja el estado: guárdalo en el componente más pequeño que lo necesite en lugar de un componente de nivel de página o un context.
- Envuelve los subárboles costosos en React.memo y estabiliza las props que les pasas con useCallback/useMemo — memo es inútil si se crea un callback nuevo en cada render.
- Marca las actualizaciones no urgentes (filtrar una lista mientras se escribe) con useTransition para que el render urgente (el propio input) se pinte primero.
Problema
const Page = () => {
const [query, setQuery] = useState("")
// every keystroke re-renders Page → Header, Sidebar, BigTable, Footer
return <>
<SearchInput value={query} onChange={setQuery} />
<BigTable rows={filterRows(rows, query)} />
</>
}
Solución
const BigTable = React.memo(({ rows }) => /* ... */)
const Page = () => {
const [query, setQuery] = useState("")
const [isPending, startTransition] = useTransition()
const rows = useMemo(() => filterRows(allRows, query), [query])
const onChange = (q) =>
startTransition(() => setQuery(q)) // input paints first, table follows
return <>
<SearchInput onChange={onChange} />
<BigTable rows={rows} />
</>
}
Escanea tu sitio gratis →