Ciclo de vida de un componente: React, Angular y Lit
1. OBJETIVO
Comparar cómo se administra el ciclo de vida de un componente en React, Angular y Lit (LitElement), usando el mismo ejemplo funcional: un contador que aumenta cada segundo mientras el componente está montado o conectado y detiene el temporizador cuando deja de estarlo.
La idea es la misma en los tres casos:
- El componente aparece.
- Se inicia un temporizador.
- El estado del contador cambia cada segundo y la interfaz se actualiza.
- El componente desaparece.
- Se limpia el temporizador para evitar que siga ejecutándose.
Nota: React es una biblioteca basada en funciones y efectos; Angular ofrece hooks de ciclo de vida en clases; LitElement es una clase de componente web con propiedades reactivas y callbacks del ciclo de vida del elemento personalizado.
2. REACT
Ejemplo: ContadorReact.jsx
import { useEffect, useState } from "react";
export default function ContadorReact() {
const [contador, setContador] = useState(0);
useEffect(() => {
// Se ejecuta después de que React confirma el renderizado.
const intervalo = setInterval(() => {
setContador(valorActual => valorActual + 1);
}, 1000);
// Limpieza: se ejecuta antes de repetir el efecto y al desmontar.
return () => {
clearInterval(intervalo);
};
}, []);
return <div>Segundos transcurridos: {contador}</div>;
}
Cómo funciona el ciclo de vida en React
- Renderizado inicial: React ejecuta
ContadorReacty produce la interfaz con el contador en 0. - Montaje y efecto: después de confirmar el renderizado,
useEffectiniciasetInterval. El arreglo vacío[]indica que el efecto no depende de valores reactivos y no necesita repetirse por cambios de estado. - Actualización: cada segundo,
setContadorcambia el estado. React vuelve a ejecutar la función del componente y actualiza el texto de la interfaz. - Desmontaje: cuando el componente se elimina, React ejecuta la función de limpieza retornada por
useEffect.clearIntervaldetiene el temporizador.
Importante: en entornos de desarrollo con React Strict Mode, React puede ejecutar un ciclo adicional de configuración y limpieza para detectar efectos incorrectos. Por eso la limpieza debe estar bien implementada.
3. ANGULAR
Ejemplo: contador.component.ts
import { Component, OnDestroy, OnInit } from "@angular/core";
@Component({
selector: "app-contador",
standalone: true,
template: `<div>Segundos transcurridos: {{ contador }}</div>`
})
export class ContadorComponent implements OnInit, OnDestroy {
contador = 0;
private intervalo?: ReturnType<typeof setInterval>;
ngOnInit(): void {
// Se ejecuta una vez después de inicializar el componente.
this.intervalo = setInterval(() => {
this.contador++;
}, 1000);
}
ngOnDestroy(): void {
// Se ejecuta cuando Angular destruye el componente.
if (this.intervalo !== undefined) {
clearInterval(this.intervalo);
}
}
}
Cómo funciona el ciclo de vida en Angular
- Creación e inicialización: Angular crea la instancia de
ContadorComponente inicializa la propiedad contador en 0. - Inicialización del componente:
ngOnInitse ejecuta una vez después de que Angular inicializa las propiedades de entrada del componente. Allí se inicia el temporizador. - Actualización: cada segundo, el callback incrementa contador. Angular detecta el cambio y actualiza la interpolación
{{ contador }}en la plantilla. - Destrucción: cuando el componente se retira de la vista, Angular llama a
ngOnDestroy. Allí se limpia el intervalo.
Nota: Angular también dispone de otros hooks, como ngOnChanges para cambios en propiedades de entrada y ngAfterViewInit para después de inicializar la vista. No son necesarios para este ejemplo.
4. LIT (LITELEMENT)
Ejemplo: contador-lit.js
import { LitElement, html } from "lit";
class ContadorLit extends LitElement {
static properties = {
contador: { type: Number }
};
constructor() {
super();
this.contador = 0;
this.intervalo = undefined;
}
connectedCallback() {
super.connectedCallback();
// Se ejecuta cuando el elemento se conecta al DOM.
this.intervalo = setInterval(() => {
this.contador++;
}, 1000);
}
disconnectedCallback() {
// Se ejecuta cuando el elemento se desconecta del DOM.
if (this.intervalo !== undefined) {
clearInterval(this.intervalo);
this.intervalo = undefined;
}
super.disconnectedCallback();
}
render() {
return html`<div>Segundos transcurridos: ${this.contador}</div>`;
}
}
customElements.define("contador-lit", ContadorLit);
Cómo funciona el ciclo de vida en LitElement
- Construcción: el constructor crea la instancia e inicializa contador en 0.
- Conexión:
connectedCallbackse ejecuta cuando el elemento se conecta al DOM. Se llama asuper.connectedCallback()y se inicia el temporizador. - Actualización reactiva: contador está declarada como propiedad reactiva. Cuando cambia, Lit programa una actualización y vuelve a ejecutar
render()para actualizar el contenido. - Desconexión:
disconnectedCallbackse ejecuta cuando el elemento se desconecta del DOM. Se limpia el temporizador y se llama al método de la clase base.
Nota: un elemento personalizado puede desconectarse y volver a conectarse. Por eso connectedCallback puede ejecutarse más de una vez durante su vida. En aplicaciones que permitan reconexiones repetidas, conviene proteger la creación del intervalo para no iniciar varios temporizadores simultáneos. En este ejemplo, el intervalo se limpia al desconectar; al reconectar se crea uno nuevo.
5. COMPARACIÓN DIRECTA
| Etapa | React | Angular | LitElement |
|---|---|---|---|
| Inicialización | Función del componente | Constructor | constructor() |
| Inicio del trabajo | useEffect | ngOnInit | connectedCallback() |
| Cambio de datos | setState / useState | Cambiar propiedad | Cambiar propiedad reactiva |
| Actualización visual | Nuevo render | Detección de cambios | render() reactivo |
| Limpieza al salir | Limpieza de useEffect | ngOnDestroy | disconnectedCallback() |
La comparación es conceptual: los hooks no son equivalentes exactos en todos sus detalles. En React, useEffect sincroniza el componente con un efecto externo; en Angular, ngOnInit y ngOnDestroy son hooks explícitos; en Lit, connectedCallback y disconnectedCallback son callbacks del ciclo de vida del elemento personalizado.
6. CONCLUSIÓN
Los tres componentes implementan el mismo comportamiento, pero expresan el ciclo de vida de manera distinta:
- React:
useEffectinicia el temporizador y la función de limpieza lo detiene. - Angular:
ngOnInitinicia el temporizador yngOnDestroylo detiene. - LitElement:
connectedCallbackinicia el temporizador ydisconnectedCallbacklo detiene.
La regla importante en los tres frameworks es la misma: todo recurso externo que se inicia, por ejemplo, un temporizador, una suscripción o un listener, debe liberarse cuando deja de ser necesario. Esto evita fugas de recursos y comportamientos duplicados.
© Arturo Juárez Monroy