10.3-Ciclo de Vida de un Componente React - Explicación PRÁCTICA
Ciclo de Vida de un Componente React - Explicación PRÁCTICA
🎯 En 10 segundos:
NACE → VIVE → MUERE
(Se monta → Se actualiza → Se desmonta)
📱 Analogía del Celular:
jsx
// Tu celular es como un componente React
CELULAR {
// 1. NACE (Montar)
- Compras el celular ✅
- Lo enciendes por primera vez 🔋
// 2. VIVE (Actualizar)
- Usas apps 📱
- Recibes notificaciones 🔔
- Cambias el fondo de pantalla 🖼️
// 3. MUERE (Desmontar)
- Se apaga 🔌
- Lo vendes 💸
}
🔄 Las 3 Fases PRINCIPALES:
FASE 1: MONTAJE (Nace)
Cuando el componente aparece por PRIMERA VEZ
jsx
function PerfilUsuario() {
// 1. Se crean los estados INICIALES
const [nombre, setNombre] = useState(''); // ← Estado inicial vacío
const [edad, setEdad] = useState(0); // ← Estado inicial 0
const [foto, setFoto] = useState('default.jpg'); // ← Estado inicial
// 2. useEffect con [] se ejecuta UNA SOLA VEZ aquí
useEffect(() => {
console.log('✅ PerfilUsuario MONTADO!');
// Ej: Cargar datos del servidor
fetch('/api/perfil').then(res => res.json())
.then(data => {
setNombre(data.nombre);
setEdad(data.edad);
setFoto(data.foto);
});
// 3. Función de LIMPIEZA (se prepara para cuando muera)
return () => {
console.log('⚠️ Preparándose para desmontar...');
// Ej: Cancelar peticiones pendientes
};
}, []); // ← Array vacío = solo al montar
// 4. Se RENDERIZA por primera vez
return (
<div>
<img src={foto} alt="Foto perfil" />
<h1>{nombre}</h1>
<p>{edad} años</p>
</div>
);
}
¿Cuándo ocurre el montaje?
jsx
// Ejemplo:
{usuarioLogueado && <PerfilUsuario />}
// Cuando usuarioLogueado pasa de false → true
// PerfilUsuario se MONTA por primera vez
FASE 2: ACTUALIZACIÓN (Vive)
Cuando el componente CAMBIA mientras está en pantalla
jsx
function Contador() {
const [contador, setContador] = useState(0);
const [color, setColor] = useState('black');
// useEffect SIN array vacío = se ejecuta en CADA actualización
useEffect(() => {
console.log(`🔄 Contador actualizado: ${contador}`);
// Cambiar color basado en el contador
if (contador > 10) setColor('red');
else if (contador > 5) setColor('orange');
else setColor('green');
}); // ← Sin array = se ejecuta en cada render
// useEffect CON dependencias = solo cuando esas cosas cambian
useEffect(() => {
console.log('🎨 Color cambiado:', color);
}, [color]); // ← Solo cuando 'color' cambia
return (
<div style={{color}}>
<h2>Contador: {contador}</h2>
<button onClick={() => setContador(contador + 1)}>
Incrementar
</button>
</div>
);
}
Flujo de actualización:
text
1. Usuario hace click en "Incrementar"
2. setContador(contador + 1) → contador cambia de 0 → 1
3. React: "¡Oh! contador cambió, debo RE-RENDERIZAR"
4. useEffect() sin array se ejecuta (porque hubo render)
5. Si color cambió, el segundo useEffect se ejecuta
6. Se muestra el nuevo valor en pantalla
FASE 3: DESMONTAJE (Muere)
Cuando el componente DESAPARECE de la pantalla
jsx
function ChatEnVivo() {
const [mensajes, setMensajes] = useState([]);
useEffect(() => {
console.log('💬 Chat MONTADO - Conectando al servidor...');
// 1. Conexión WebSocket (se inicia al montar)
const socket = new WebSocket('wss://chat-server.com');
socket.onmessage = (event) => {
setMensajes(prev => [...prev, event.data]);
};
// 2. FUNCIÓN DE LIMPIEZA (la parte MÁS IMPORTANTE)
return () => {
console.log('💀 Chat DESMONTADO - Cerrando conexión...');
socket.close(); // ← EVITA FUGAS DE MEMORIA
// Si no hacemos esto, el socket sigue escuchando
// aunque el componente ya no exista
};
}, []);
return (
<div>
{mensajes.map((msg, i) => <p key={i}>{msg}</p>)}
</div>
);
}
// En el componente padre:
function App() {
const [mostrarChat, setMostrarChat] = useState(true);
return (
<div>
<button onClick={() => setMostrarChat(!mostrarChat)}>
{mostrarChat ? 'Ocultar Chat' : 'Mostrar Chat'}
</button>
{/* Cuando mostrarChat sea false, ChatEnVivo se DESMONTA */}
{mostrarChat && <ChatEnVivo />}
</div>
);
}
📊 RESUMEN VISUAL del Ciclo Completo:
text
┌─────────────────────────────────────┐
│ APP SE INICIA │
└───────────────────┬─────────────────┘
│
¿Mostrar Componente? ──NO──┐
│ │
SÍ │
│ │
┌───────▼───────┐ │
│ MONTAJE │ │
│ (Nace) │ │
└───────┬───────┘ │
│ │
┌───────▼───────┐ │
│ useState() │ │
│ se ejecuta │ │
└───────┬───────┘ │
│ │
┌───────▼───────┐ │
│ Primera │ │
│ Render │ │
└───────┬───────┘ │
│ │
┌───────▼───────┐ │
│ useEffect() │ │
│ (solo montaje)│ │
└───────┬───────┘ │
│ │
┌───────────┴───────────┐ │
│ │ │
┌───────▼───────┐ ┌───────▼───────┐
│ ACTUALIZACIÓN│ │ DESMONTAJE │
│ (Vive) │ │ (Muere) │
└───────┬───────┘ └───────┬───────┘
│ │
┌───────▼───────┐ ┌───────▼───────┐
│ Estado cambia │ │Función de │
│ o props │ │limpieza │
│ cambian │ │se ejecuta │
└───────┬───────┘ └───────────────┘
│
┌───────▼───────┐
│ Re-render │
│ automático │
└───────┬───────┘
│
┌───────▼───────┐
│ useEffect() │
│ (si depende │
│ del cambio) │
└───────────────┘
🎯 Ejemplo PRÁCTICO del Mundo Real:
jsx
// Componente: Reproductor de Música
function MusicPlayer({ cancionId }) {
// FASE 1: MONTAJE (cuando seleccionas una canción)
const [volumen, setVolumen] = useState(50);
const [reproduciendo, setReproduciendo] = useState(false);
const [tiempo, setTiempo] = useState(0);
useEffect(() => {
console.log(`🎵 Cargando canción ${cancionId}...`);
// Cargar archivo de audio
// Configurar event listeners
return () => {
console.log('⏹️ Deteniendo reproducción...');
// Limpiar event listeners
// Liberar memoria del audio
};
}, [cancionId]); // Se ejecuta al montar Y cuando cancionId cambia
// FASE 2: ACTUALIZACIÓN (mientras suena la canción)
useEffect(() => {
if (reproduciendo) {
console.log('▶️ Reproduciendo...');
const intervalo = setInterval(() => {
setTiempo(t => t + 1);
}, 1000);
return () => clearInterval(intervalo);
}
}, [reproduciendo]); // Solo cuando reproduciendo cambia
// FASE 3: DESMONTAJE (cuanto cambias de canción o cierras)
// (la función de limpieza del primer useEffect se ejecuta)
return (
<div>
<button onClick={() => setReproduciendo(!reproduciendo)}>
{reproduciendo ? 'Pausar' : 'Reproducir'}
</button>
<p>Tiempo: {tiempo}s</p>
<input
type="range"
value={volumen}
onChange={e => setVolumen(e.target.value)}
/>
</div>
);
}
🚨 ERRORES COMUNES que EVITAR:
❌ Error: Actualizar estado de componente desmontado
jsx
useEffect(() => {
fetch('/api/datos')
.then(res => res.json())
.then(data => {
setDatos(data); // ⚠️ ERROR si componente se desmonta antes
});
}, []);
✅ Solución: Verificar si está montado
jsx
useEffect(() => {
let estaMontado = true;
fetch('/api/datos')
.then(res => res.json())
.then(data => {
if (estaMontado) { // ✅ Verificación
setDatos(data);
}
});
return () => { estaMontado = false; }; // ✅ Cleanup
}, []);
📌 Reglas de Oro PRÁCTICAS:
useEffect con [] vacío → Solo al montar (y cleanup al desmontar)
useEffect con [dependencia] → Al montar Y cuando esa cosa cambia
useEffect sin array → En cada render (¡cuidado con loops infinitos!)
SIEMPRE limpia suscripciones, timeouts, listeners en el cleanup
El estado LOCAL muere cuando el componente se desmonta
Para datos importantes → guárdalos en el padre, contexto, o servidor
🎯 En 1 línea:
"Los componentes nacen (mount), cambian (update), y mueren (unmount) - y tú controlas qué pasa en cada etapa"
Comentarios
Publicar un comentario