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:

  1. useEffect con [] vacío → Solo al montar (y cleanup al desmontar)

  2. useEffect con [dependencia] → Al montar Y cuando esa cosa cambia

  3. useEffect sin array → En cada render (¡cuidado con loops infinitos!)

  4. SIEMPRE limpia suscripciones, timeouts, listeners en el cleanup

  5. El estado LOCAL muere cuando el componente se desmonta

  6. 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

Entradas más populares de este blog

9.3-Tutorial de Componentes React con Props -SSS

9.6-Ciclo de Vida de un Componente React

9-Componentes en React-estado