Ciclo de vida de los Web Components: Guía para principiantes
Ciclo de vida de los Web Components: Guía para principiantes
El ciclo de vida de los Web Components describe las etapas o fases que atraviesa un componente personalizado desde su creación hasta su eliminación. Conocer este ciclo es importante porque permite ejecutar código JavaScript en momentos clave (por ejemplo, al insertarse el elemento en la página o al cambiar sus atributos) y así construir componentes web robustos y eficientes. En cada fase hay un método especial (llamado lifecycle callback) que el navegador invoca automáticamente. Aprender a usar estos métodos ayuda a organizar la inicialización del componente, gestionar recursos (como eventos o temporizadores) y responder a cambios dinámicos.
Constructor
Definición: El constructor() es un método de la clase del elemento personalizado que se ejecuta cuando se crea una instancia del componente, antes de que aparezca en el DOMdesarrolloweb.comdesarrolloweb.com.
¿Cuándo se ejecuta?: Se invoca al instanciar el elemento, por ejemplo con
document.createElement('mi-elemento')
o cuando el navegador parsea el HTML que contiene la etiqueta. Este es el primer paso del ciclo de vidadesarrolloweb.com.Funcionalidad: Dentro del constructor podemos preparar el estado inicial: llamar a
super()
, crear o adjuntar elementos internos (como un shadow DOM), inicializar propiedades y configurar escuchadores de eventos que no dependan aún del DOM.Ventajas: Permite configurar el componente desde cero. Como se ejecuta al instanciar, incluso si el elemento no está en la página, es útil para inicializar propiedades o crear estructuras internas. Sin embargo, según MDN es recomendable no manipular los atributos ni hijos del elemento en el constructordeveloper.mozilla.orgdesarrolloweb.com.
Ejemplo en JavaScript puro: (al crear el elemento se ejecuta el constructor)
class MiElemento extends HTMLElement {
constructor() {
super();
// Este código corre al instanciar el componente
console.log('Constructor de MiElemento');
// Creamos un shadow DOM y contenido inicial
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `¡Hola desde el constructor!
`;
}
}
customElements.define('mi-elemento', MiElemento);
// Creación del elemento dispara el constructor
document.createElement('mi-elemento'); // Muestra "Constructor de MiElemento"
connectedCallback
Definición:
connectedCallback()
es el método que se invoca cada vez que el componente se añade al documento (es decir, cuando se inserta en el DOM)¿Cuándo se ejecuta?: Se activa al insertar el elemento en la página. Por ejemplo, al hacer
document.body.appendChild(document.createElement('mi-elemento'))
o al parsear una etiqueta<mi-elemento>
en el HTML. Puede ocurrir varias veces si el elemento se mueve dentro del DOM.Funcionalidad: Aquí se recomienda hacer la mayor parte de la inicialización: actualizar la interfaz, añadir contenido, establecer atributos por defecto, adjuntar shadow DOM dinámicamente o configurar escuchas de eventos basados en la presencia del elemento en la página. Según MDN, se sugiere preferir
connectedCallback()
para inicializar en lugar del constructorVentajas: Permite reaccionar justo cuando el componente está visible. Ideal para operaciones que requieren que el elemento ya esté en el DOM (como medir dimensiones o establecer sub-árboles de DOM). Al desconectar y reconectar un elemento, este método se vuelve a llamar, lo cual puede servir para reactivar funciones pausadas.
Ejemplo en JavaScript puro: (al agregar el elemento al DOM)
class MiElementoConectado extends HTMLElement {
connectedCallback() {
console.log('MiElementoConectado añadido al DOM');
// Se puede actualizar el contenido o estilos aquí
this.innerHTML = '¡MiElementoConectado está ahora en la página!
';
}
}
customElements.define('mi-elemento-conectado', MiElementoConectado);
// Al insertar en el DOM, se ejecuta connectedCallback
const elem = document.createElement('mi-elemento-conectado');
document.body.appendChild(elem); // Muestra el mensaje y agrega contenido
disconnectedCallback
Definición:
disconnectedCallback()
se invoca cada vez que el elemento se elimina del DOM¿Cuándo se ejecuta?: Se activa al remover el componente de la página, por ejemplo usando
element.remove()
oparentNode.removeChild(element)
. Cada vez que el elemento se desconecta del documento, se llama a este método.Funcionalidad: En este callback se deben limpiar recursos o cancelar tareas pendientes: remover escuchadores de eventos globales, cancelar timers, desconectar observers, etc. Esto evita fugas de memoria.
Ventajas: Ayuda a mantener el rendimiento y evitar problemas. Por ejemplo, si en
connectedCallback()
añadimos unsetInterval()
, aquí podemos borrarlo. También es útil para detener animaciones o procesos cuando el componente ya no está visible.
Ejemplo en JavaScript puro: (al quitar el elemento del DOM)
class MiElementoDesconectado extends HTMLElement {
disconnectedCallback() {
console.log('MiElementoDesconectado removido del DOM');
// Aquí limpiaríamos recursos, como:
// clearInterval(miIntervalo); o document.removeEventListener(...)
}
}
customElements.define('mi-elemento-desconectado', MiElementoDesconectado);
const elem = document.createElement('mi-elemento-desconectado');
document.body.appendChild(elem); // Conectamos el elemento
document.body.removeChild(elem); // Muestra "removido del DOM" en la consola
adoptedCallback
Definición:
adoptedCallback()
es un método que se ejecuta cuando el elemento se mueve a otro documento (por ejemplo, al ser adoptado por undocument
distinto)¿Cuándo se ejecuta?: Ocurre en casos especiales. Por ejemplo, si tenemos el componente en el
window.document
y luego lo insertamos en otro iframe (u otro documento), se invoca este callback. Este escenario es poco común en aplicaciones típicas.Funcionalidad: Permite reaccionar a la migración del elemento a un nuevo documento. Podríamos volver a inicializar algunos detalles específicos del nuevo contexto.
Ventajas: Aunque se usa raramente, ofrece flexibilidad si el componente necesita adaptarse tras moverse de ventana o iframe. Por ejemplo, podríamos restablecer el estilo o reconfigurar datos que dependen del documento padre.
Ejemplo en JavaScript puro: (al adoptar el elemento en otro documento)
class MiElementoAdoptado extends HTMLElement {
adoptedCallback() {
console.log('MiElementoAdoptado fue movido a otro documento');
// Aquí podríamos actualizar el componente tras la migración
}
}
customElements.define('mi-elemento-adoptado', MiElementoAdoptado);
// En un escenario real, este método se ejecutaría al mover el elemento a un nuevo documento.
// No hay un ejemplo sencillo de código puro sin múltiples documentos.
attributeChangedCallback
Definición:
attributeChangedCallback(name, oldValue, newValue)
se invoca cada vez que un atributo observado del elemento se añade, quita o modifica. Específicamente, sólo se ejecuta para los atributos que listamos en el arreglo estáticoobservedAttributes
.¿Cuándo se ejecuta?: Se activa justo después de que cambia un atributo observado, incluso durante el parseo inicial del elemento. Recibe el nombre del atributo y sus valores antiguo y nuevo.
Funcionalidad: Sirve para reaccionar dinámicamente a cambios en los atributos del componente. Por ejemplo, actualizar el estilo o recalcular algún dato interno cuando el usuario modifica una propiedad del componente.
Ventajas: Permite crear componentes reactivos. Al vincular atributos HTML con la lógica del componente, podemos cambiar propiedades usando HTML (
<mi-elemento color="red">
) o JavaScript (el.setAttribute('color', 'red')
) y que el componente responda automáticamente.
Ejemplo en JavaScript puro: (al cambiar un atributo observado)
class MiElementoAtributo extends HTMLElement {
// Declaramos que vamos a observar el atributo "color"
static get observedAttributes() { return ['color']; }
attributeChangedCallback(name, oldValue, newValue) {
console.log(`Atributo ${name} cambió de ${oldValue} a ${newValue}`);
if (name === 'color') {
// Actualizamos el fondo cuando cambia "color"
this.style.backgroundColor = newValue;
}
}
connectedCallback() {
// Inicialmente definimos un estilo base
this.style.display = 'block';
this.textContent = 'MiElementoAtributo';
}
}
customElements.define('mi-elemento-atributo', MiElementoAtributo);
// Cambiar el atributo 'color' dispara el callback
const elem = document.createElement('mi-elemento-atributo');
document.body.appendChild(elem);
elem.setAttribute('color', 'lightblue');
// Console: "Atributo color cambió de null a lightblue" y se actualiza el estilo
Conclusión
En resumen, el ciclo de vida de los Web Components consta de varias fases clave – constructor, connectedCallback, disconnectedCallback, adoptedCallback y attributeChangedCallback – que el navegador invoca automáticamente en distintos momentos. Cada una cumple una función: el constructor inicializa el componente, connectedCallback reacciona al insertar el elemento en el DOM, disconnectedCallback al quitarlo, adoptedCallback al moverlo a otro documento y attributeChangedCallback al cambiar sus atributos observados. Entender y utilizar correctamente estos métodos permite crear componentes personalizados más robustos, manteniendo el código organizado y manejando adecuadamente recursos y actualizaciones dinámicas.
Links de referencia: