¿Cuándo se re-renderiza un componente en React?
Ver respuesta — intenta responderla en voz alta primero
Un componente se re-renderiza cuando cambia su estado, cuando su padre se re-renderiza o cuando cambia un context que consume. Ojo: "renderizar" significa que React vuelve a ejecutar la función del componente; no significa que el DOM se actualice, eso solo pasa si el resultado cambió.
Renderizar un componente es, literalmente, ejecutar su función para obtener JSX nuevo. Las tres causas de un re-render:
- Cambio de estado: llamas a la función
setde unuseState(o similar) con un valor distinto. - Re-render del padre: si el padre se renderiza, por defecto todos sus hijos también, aunque sus props no hayan cambiado. Por eso cambiar una prop no es una causa independiente: las props nuevas llegan porque el padre se re-renderizó.
- Cambio de context: si el componente consume un context con
useContexty el valor del provider cambia.
¿Y el DOM? Aquí entra la reconciliación:
- React ejecuta tu componente y obtiene una descripción ligera de la UI en objetos de JavaScript (el famoso Virtual DOM).
- La compara con la del render anterior (diffing) y aplica al DOM real solo las diferencias.
Por eso re-renderizar es barato la mayoría de las veces: si nada cambió en el resultado, React no toca el DOM. Piensa en el Virtual DOM como un borrador: es más rápido corregir el borrador y pasar en limpio solo los cambios que reescribir toda la página.
import { useState } from "react";
function Reloj({ hora }: { hora: number }) {
console.log("render de Reloj");
return <p>Segundos: {hora}</p>;
}
function Etiqueta() {
console.log("render de Etiqueta"); // también se ejecuta por el padre
return <span>Contador de la app</span>;
}
function App() {
const [segundos, setSegundos] = useState(0);
console.log("render de App");
return (
<div>
<Etiqueta />
<Reloj hora={segundos} />
<button onClick={() => setSegundos((prev) => prev + 1)}>Avanzar</button>
</div>
);
}
// Al hacer clic: consola -> "render de App", "render de Etiqueta",
// "render de Reloj" (Etiqueta se re-renderiza porque su padre lo hizo).
// En el DOM solo cambia el texto "Segundos: N": React comparó el
// resultado y el <span> de Etiqueta quedó idéntico.
Mutar el estado y esperar un re-render:
const [usuario, setUsuario] = useState({ nombre: "Ana" });
const renombrar = () => {
usuario.nombre = "Luis"; // MAL: mutación, la referencia es LA MISMA
setUsuario(usuario); // React compara con Object.is y no re-renderiza
};
// BIEN: referencia nueva => React detecta el cambio y re-renderiza
const renombrarBien = () => setUsuario((prev) => ({ ...prev, nombre: "Luis" }));
React decide re-renderizar comparando el valor nuevo con el anterior. Si mutas el objeto, la referencia no cambia y React asume que no hay nada que hacer; por eso siempre se crea un objeto o arreglo nuevo.
"Un componente se re-renderiza por tres motivos: cambió su propio estado, se re-renderizó su padre, o cambió un context que consume. Renderizar significa que React vuelve a ejecutar la función del componente para obtener el JSX nuevo; no implica tocar el DOM. Después viene la reconciliación: React compara la descripción nueva con la anterior usando el Virtual DOM y aplica al DOM real solo las diferencias. Por eso un re-render suele ser barato, y solo optimizo con
memoouseMemocuando de verdad detecto un problema de rendimiento."
Sin ejecutar el código, predice qué imprime la consola al hacer clic una vez en el botón, y qué cambia en el DOM.
function Hijo() {
console.log("render Hijo");
return <p>Soy el hijo</p>;
}
function Padre() {
const [n, setN] = useState(0);
console.log("render Padre");
return (
<div>
<Hijo />
<button onClick={() => setN(n + 1)}>n = {n}</button>
</div>
);
}
Ver solución
// Consola al hacer clic: "render Padre" y luego "render Hijo".
// Padre se re-renderiza porque cambió su estado (n pasó de 0 a 1); Hijo,
// porque su padre se renderizó, aunque no recibe props.
// En el DOM solo cambia el texto del botón: "n = 0" -> "n = 1". El <p> del
// hijo produjo el mismo resultado, así que la reconciliación no toca ese
// nodo: render no es igual a actualizar el DOM.