Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusLos 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.
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
// 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.
Aprendizajes de esta lección de Angular
- 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.
Completa este curso de Angular y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs