Angular
Tutorial Angular: Ciclo de vida de componentes en Angular
Angular: ciclo de vida de componentes y hooks. Explora las interfaces y métodos asociados con los hooks del ciclo de vida de los componentes en Angular para un desarrollo eficiente.
Aprende Angular GRATIS y certifícateLos componentes en Angular tienen un ciclo de vida que comienza con la creación del componente y termina con su destrucción.
Durante el ciclo de vida de un componente, Angular invoca varios métodos del componente en momentos específicos, conocidos como métodos del ciclo de vida.
Estos métodos permiten a los desarrolladores realizar acciones en diferentes etapas del ciclo de vida del componente.
Creación de un componente
Constructor
En esta etapa, se crea la instancia del componente y se inicializan sus propiedades.
El constructor es una función especial de TypeScript que se llama automáticamente al crear una instancia de la clase. Es el primer método que se ejecuta en el ciclo de vida del componente.
El constructor es ideal para inyectar dependencias y realizar configuraciones iniciales, como suscribirse a servicios, inicializar variables, o configurar propiedades del componente.
Sin embargo, es importante tener en cuenta que en el constructor no se deben ejecutar tareas que dependen de la vista del componente, ya que esta aún no ha sido inicializada.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-example',
template: '<p>{{ message }}</p>'
})
export class ExampleComponent implements OnInit {
message: string;
constructor() {
this.message = 'Hello, Angular!';
console.log('Constructor executed');
}
ngOnInit(): void {
console.log('ngOnInit executed');
}
}
OnInit
En esta etapa, después de que se haya inicializado el componente, se ejecuta el método ngOnInit()
.
Se utiliza para tareas de inicialización adicionales y lógica que debe realizarse después de que todas las propiedades del componente estén listas.
Es un buen lugar para inicializar datos que provienen de servicios externos.
import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
export class ExampleComponent implements OnInit, OnChanges {
@Input() name: string;
message: string;
constructor() {
this.message = 'Hello, Angular!';
console.log('Constructor executed');
}
ngOnInit(): void {
console.log('ngOnInit executed');
}
ngOnChanges(changes: SimpleChanges): void {
console.log('ngOnChanges executed', changes);
}
}
OnChanges
Cuando una propiedad de entrada del componente cambia, el método ngOnChanges()
se ejecuta.
Es útil para reaccionar a los cambios en las propiedades de entrada (@Input
) del componente.
Este método recibe un objeto SimpleChanges
que contiene los cambios de las propiedades de entrada.
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
export class ExampleComponent implements OnChanges {
@Input() name: string | undefined;
ngOnChanges(changes: SimpleChanges): void {
console.log('ngOnChanges executed', changes);
// Ejemplo de reacción a cambios en propiedades de entrada
if (changes['name']) {
console.log('Name changed:', changes['name'].currentValue);
}
}
}
Actualización de un componente
Cuando hay cambios en los datos o en la vista, Angular revisa el componente y realiza las actualizaciones necesarias.
Los métodos relevantes en esta fase son:
DoCheck
En esta etapa, Angular verifica manualmente los cambios que no ha detectado automáticamente.
Puede ser utilizada para realizar tareas de detección de cambios personalizadas.
Este método se llama con mucha frecuencia, por lo que es importante que su implementación sea eficiente para evitar problemas de rendimiento.
import { Component, DoCheck, Input, IterableDiffers, IterableDiffer, IterableChangeRecord } from '@angular/core';
@Component({
selector: 'app-example',
standalone: true,
template: `
<div>
<p>{{ message }}</p>
<button (click)="addItem()">Add Item</button>
<button (click)="removeItem()">Remove Item</button>
<button (click)="changeMessage()">Change Message</button>
@if (items.length) {
<ul>
@for (item of items; track $index) {
<li>{{ item }}</li>
}
</ul>
} @else {
<p>No items to display.</p>
}
</div>
`
})
export class ExampleComponent implements DoCheck {
@Input() items: string[] = ['Item 1', 'Item 2', 'Item 3'];
@Input() message: string = 'Hello, Angular!';
private itemsDiffer: IterableDiffer<any>;
private previousMessage: string;
constructor(private differs: IterableDiffers) {
this.itemsDiffer = this.differs.find(this.items).create();
this.previousMessage = this.message;
}
ngDoCheck(): void {
console.log('ngDoCheck executed');
// Detectar cambios en la lista de items
const itemsChanges = this.itemsDiffer.diff(this.items);
if (itemsChanges) {
itemsChanges.forEachAddedItem((record: IterableChangeRecord<any>) => {
console.log('Item added:', record.item);
});
itemsChanges.forEachRemovedItem((record: IterableChangeRecord<any>) => {
console.log('Item removed:', record.item);
});
}
// Detectar cambios en la propiedad message
if (this.message !== this.previousMessage) {
console.log('Message changed from', this.previousMessage, 'to', this.message);
this.previousMessage = this.message;
}
}
addItem() {
this.items.push(`Item ${this.items.length + 1}`);
}
removeItem() {
this.items.pop();
}
changeMessage() {
this.message = 'Message changed from ExampleComponent';
}
}
AfterContentInit
Una vez que el contenido proyectado (contenido dentro de las etiquetas <ng-content>
) se ha inicializado, se ejecuta el método ngAfterContentInit()
.
Este método es útil para realizar tareas que dependen del contenido proyectado en el componente.
// parent.component.ts
import { Component, AfterContentInit, ContentChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-parent',
standalone: true,
template: `
<div>
<ng-content></ng-content>
@if (contentInitialized) {
<p>Contenido proyectado: {{ projectedText }}</p>
}
</div>
`
})
export class ParentComponent implements AfterContentInit {
@ContentChild('projectedContent', { static: true }) content!: ElementRef;
contentInitialized = false;
projectedText = '';
ngAfterContentInit(): void {
console.log('ngAfterContentInit ejecutado');
this.projectedText = this.content.nativeElement.textContent;
this.contentInitialized = true;
}
}
// example.component.ts
@Component({
selector: 'app-example',
standalone: true,
imports: [ParentComponent],
template: `
<app-parent>
<p #projectedContent>
@if (showContent) {
Contenido proyectado dinámico
} @else {
Contenido alternativo
}
</p>
</app-parent>
<button (click)="toggleContent()">Cambiar contenido</button>
`
})
export class ExampleComponent {
showContent = true;
toggleContent() {
this.showContent = !this.showContent;
}
}
En este ejemplo se muestra a no solo el uso de AfterContentInit
, sino también cómo el contenido proyectado puede cambiar dinámicamente y cómo el componente padre puede reaccionar a estos cambios.
AfterContentChecked
Después de cada verificación del contenido proyectado, se ejecuta el método ngAfterContentChecked()
.
Este método se llama después de cada ciclo de detección de cambios y puede utilizarse para realizar acciones adicionales después de que Angular haya verificado el contenido proyectado.
// parent.component.ts
import { Component, AfterContentChecked, ContentChild, ElementRef, signal } from '@angular/core';
@Component({
selector: 'app-parent',
standalone: true,
template: `
<div>
<ng-content></ng-content>
@if (contentChecked()) {
<p>Último contenido verificado: {{ lastCheckedContent() }}</p>
}
</div>
`
})
export class ParentComponent implements AfterContentChecked {
@ContentChild('projectedContent', { static: true }) content!: ElementRef;
contentChecked = signal(false);
lastCheckedContent = signal('');
ngAfterContentChecked(): void {
console.log('ngAfterContentChecked ejecutado');
const currentContent = this.content.nativeElement.textContent;
console.log('Contenido proyectado verificado:', currentContent);
this.lastCheckedContent.set(currentContent);
this.contentChecked.set(true);
}
}
// example.component.ts
@Component({
selector: 'app-example',
standalone: true,
imports: [ParentComponent],
template: `
<app-parent>
<p #projectedContent>{{ dynamicContent() }}</p>
</app-parent>
<button (click)="updateContent()">Actualizar contenido</button>
`
})
export class ExampleComponent {
dynamicContent = signal('Contenido proyectado inicial');
updateCount = 0;
updateContent() {
this.updateCount++;
this.dynamicContent.set(`Contenido proyectado actualizado ${this.updateCount} veces`);
}
}
En este ejemplo el componente padre (ParentComponent
) verifica y muestra el contenido proyectado cada vez que cambia, utilizando señales para manejar el estado de forma reactiva. El componente hijo (ExampleComponent
) permite actualizar dinámicamente el contenido proyectado, lo que desencadena la verificación en el padre.
AfterViewInit
Una vez que la vista y los elementos hijos se han inicializado, se ejecuta el método ngAfterViewInit()
.
Es útil para realizar acciones que dependen de las vistas de los componentes hijos, como la configuración de elementos del DOM o la inicialización de bibliotecas que requieren acceso al DOM.
// child.component.ts
import { Component, AfterViewInit, ViewChild, ElementRef, signal } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `<p>{{ message() }}</p>`
})
export class ChildComponent {
message = signal('Componente hijo inicial');
updateMessage(newMessage: string) {
this.message.set(newMessage);
}
}
// parent.component.ts
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: `
<app-child #childComponent />
<button (click)="updateChildMessage()">Actualizar hijo</button>
@if (childInitialized()) {
<p>Estado del hijo: {{ childState() }}</p>
}
`
})
export class ParentComponent implements AfterViewInit {
@ViewChild('childComponent') child!: ChildComponent;
childInitialized = signal(false);
childState = signal('');
ngAfterViewInit(): void {
console.log('ngAfterViewInit ejecutado');
console.log('Componente hijo:', this.child);
this.childInitialized.set(true);
this.updateChildState();
}
updateChildMessage() {
this.child.updateMessage('Mensaje actualizado del hijo');
this.updateChildState();
}
private updateChildState() {
this.childState.set(this.child.message());
}
}
En este ejemplo el componente padre (ParentComponent
) accede y manipula el componente hijo (ChildComponent
) después de su inicialización. Utiliza señales para manejar el estado de forma reactiva y muestra cómo interactuar con las vistas de los componentes hijos una vez inicializadas.
AfterViewChecked
Después de cada verificación de la vista y los elementos hijos, se ejecuta el método ngAfterViewChecked()
.
Este método se llama después de cada ciclo de detección de cambios y puede utilizarse para realizar acciones adicionales después de que Angular haya verificado la vista del componente.
// child.component.ts
import { Component, AfterViewChecked, ViewChild, signal, effect } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `<p>{{ counter() }}</p>`
})
export class ChildComponent {
counter = signal(0);
increment() {
this.counter.update(value => value + 1);
}
}
// parent.component.ts
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: `
<app-child #childComponent />
<button (click)="incrementChild()">Incrementar hijo</button>
<p>Última verificación: {{ lastCheckedValue() }}</p>
`
})
export class ParentComponent implements AfterViewChecked {
@ViewChild('childComponent') child!: ChildComponent;
lastCheckedValue = signal(0);
checkCount = signal(0);
constructor() {
effect(() => {
console.log(`Vista verificada ${this.checkCount()} veces. Último valor: ${this.lastCheckedValue()}`);
});
}
ngAfterViewChecked(): void {
this.checkCount.update(count => count + 1);
this.lastCheckedValue.set(this.child.counter());
}
incrementChild() {
this.child.increment();
}
}
En este ejemplo el componente padre (ParentComponent
) verifica el estado del componente hijo (ChildComponent
) después de cada ciclo de detección de cambios. Utiliza señales y efectos para manejar y mostrar de forma reactiva el estado de las verificaciones.
Destrucción de un componente
Cuando un componente ya no es necesario, Angular lo destruye para liberar recursos.
OnDestroy
El método ngOnDestroy()
se llama justo antes de que Angular destruya el componente.
Este método es ideal para realizar tareas de limpieza, como desuscribirse de observables, eliminar temporizadores o liberar recursos que el componente esté utilizando.
import { Component, OnDestroy, Input, inject } from '@angular/core';
import { Subscription, interval } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DataService } from './data.service';
@Component({
selector: 'app-example',
standalone: true,
template: `
<div>
<p>{{ message }}</p>
@if (items.length) {
<ul>
@for (item of items; track $index) {
<li>{{ item }}</li>
}
</ul>
} @else {
<p>No hay elementos para mostrar.</p>
}
</div>
`
})
export class ExampleComponent implements OnDestroy {
@Input() items: string[] = [];
@Input() message = 'Hello, Angular!';
private dataService = inject(DataService);
private intervalSubscription: Subscription;
constructor() {
// Suscripción a un observable del servicio usando takeUntilDestroyed
this.dataService.getData().pipe(
takeUntilDestroyed()
).subscribe(data => {
this.items = data;
});
// Configuración de un intervalo usando RxJS
this.intervalSubscription = interval(1000).pipe(
takeUntilDestroyed()
).subscribe(() => {
console.log('Intervalo ejecutado');
});
}
ngOnDestroy(): void {
console.log('ngOnDestroy ejecutado');
// La suscripción al servicio de datos se maneja automáticamente por takeUntilDestroyed
// Limpiar suscripción del intervalo (por si acaso)
if (this.intervalSubscription) {
this.intervalSubscription.unsubscribe();
console.log('Suscripción del intervalo cancelada');
}
}
}
En este ejemplo se utiliza takeUntilDestroyed()
para manejar automáticamente la cancelación de suscripciones, simplificando la limpieza de recursos. El componente se suscribe a un servicio de datos y configura un intervalo, demostrando cómo gestionar eficientemente los recursos y evitar fugas de memoria en la destrucción del componente.
Comparación de métodos similares del ciclo de vida
Constructor vs OnInit
- Constructor: Se llama cuando se crea la instancia del componente. Es ideal para inyectar dependencias, pero no para inicializar datos.
- OnInit: Se ejecuta una vez que Angular ha inicializado todas las propiedades vinculadas a datos. Es el lugar recomendado para inicializar datos y realizar configuraciones iniciales.
OnChanges vs DoCheck
- OnChanges: Se ejecuta cuando Angular detecta cambios en las propiedades de entrada (@Input
). Es eficiente para reaccionar a cambios específicos en las entradas del componente.
- DoCheck: Se ejecuta durante cada ciclo de detección de cambios, permitiendo una detección de cambios personalizada. Es más flexible pero menos eficiente, por lo que debe usarse con precaución.
AfterContentInit vs AfterViewInit
- AfterContentInit: Se ejecuta después de que Angular proyecta el contenido externo en la vista del componente. Es útil para inicializar algo que depende del contenido proyectado.
- AfterViewInit: Se ejecuta después de que Angular inicializa la vista del componente y sus vistas hijas. Es ideal para realizar acciones que requieren que los elementos del DOM estén completamente renderizados.
AfterContentChecked vs AfterViewChecked
- AfterContentChecked: Se llama después de cada verificación del contenido proyectado. Útil para detectar cambios en el contenido proyectado después de cada ciclo de detección.
- AfterViewChecked: Se llama después de cada verificación de la vista del componente y sus vistas hijas. Permite realizar acciones adicionales después de que Angular actualiza el DOM.
Ejercicios de esta lección Ciclo de vida de componentes en Angular
Evalúa tus conocimientos de esta lección Ciclo de vida de componentes en Angular con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Signals en Angular
Guards funcionales
Decodificar JWT en Angular
Servicio con HttpClient
Ciclo de vida de componentes en Angular
Gestión de productos de Fake Store API
Data binding en Angular
Routes sin módulos en Angular
Router en Angular
Instalación de Angular
Route Guards basados en interfaces
La directiva @if en Angular
Formularios reactivos en Angular
Servicios en Angular
Interceptor funcional
Servicio con Array
La directiva @for en Angular
Interceptores HTTP
Componentes standalone true
Formularios con ngModel en Angular
Routes en Angular
Comunicación entre componentes Angular
Parámetros en rutas con ActivatedRoute
CRUD de Restaurantes y Platos
Tablas en Angular Material
Formulario de registro de usuarios
Instalación y uso de NgBoostrap
Desarrollo de componentes Angular
JWT en Angular
Formularios reactivos en Angular
Formularios en Angular Material
Layout con Angular Material
Effects en Angular
Data binding
HttpClient en servicios de Angular
Desarrollo de módulos Angular
Comandos Angular CLI
Subir archivo en formularios
La directiva routerLink en Angular
Todas las lecciones de Angular
Accede a todas las lecciones de Angular y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Instalación Angular
Introducción Y Entorno
Comandos Angular Cli
Introducción Y Entorno
Desarrollo De Componentes Angular
Componentes
Data Binding En Angular
Componentes
Ciclo De Vida De Componentes En Angular
Componentes
Comunicación Entre Componentes Angular
Componentes
La Directiva @If En Angular
Componentes
La Directiva @For En Angular
Componentes
Componentes Standalone
Componentes
Desarrollo De Módulos Angular
Módulos
Routes En Angular
Enrutado Y Navegación
Router En Angular
Enrutado Y Navegación
La Directiva Routerlink En Angular
Enrutado Y Navegación
Parámetros En Rutas Con Activatedroute
Enrutado Y Navegación
Routes Sin Módulos En Angular
Enrutado Y Navegación
Servicios En Angular
Servicios E Inyección De Dependencias
Httpclient En Servicios De Angular
Servicios E Inyección De Dependencias
Formularios Con Ngmodel En Angular
Formularios
Formularios Reactivos En Angular
Formularios
Subir Archivo En Formularios
Formularios
Layout Con Angular Material
Integración Con Angular Material
Tablas En Angular Material
Integración Con Angular Material
Formularios En Angular Material
Integración Con Angular Material
Instalación Y Uso De Ngboostrap
Integración Con Bootstrap Css
Signals En Angular
Signals Y Reactividad
Effects En Angular
Signals Y Reactividad
Route Guards Basados En Interfaces
Autenticación Y Autorización
Guards Funcionales
Autenticación Y Autorización
Interceptores Http Basados En Interfaz
Autenticación Y Autorización
Interceptores Http Funcionales
Autenticación Y Autorización
Seguridad Jwt En Angular
Autenticación Y Autorización
Decodificar Tokens Jwt En Angular
Autenticación Y Autorización
Certificados de superación de Angular
Supera todos los ejercicios de programación del curso de Angular y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el ciclo de vida de un componente en Angular.
- Dominar los métodos del ciclo de vida de un componente.
- Identificar y diferenciar entre las diversas etapas del ciclo de vida de un componente.