Hooks de ciclo de vida

Intermedio
Angular
Angular
Actualizado: 04/05/2026

Hooks de Inicialización y cambios

Los hooks de ciclo de vida son métodos especiales que Angular ejecuta automáticamente en momentos específicos durante la vida de un componente. Estos hooks nos permiten ejecutar código personalizado cuando ocurren eventos importantes como la inicialización del componente o cuando cambian sus propiedades de entrada.

El orden de ejecución es estable y conocer su secuencia ayuda a decidir en qué hook colocar cada tipo de lógica.

%%{init: {'theme': 'default'}}%%
flowchart TB
    A[Constructor] --> B[ngOnChanges primera vez]
    B --> C[ngOnInit]
    C --> D[ngDoCheck]
    D --> E[ngAfterContentInit]
    E --> F[ngAfterContentChecked]
    F --> G[ngAfterViewInit]
    G --> H[ngAfterViewChecked]
    H --> I{Cambio de estado}
    I -->|si| D
    I -->|destrucción| J[ngOnDestroy]

Los hooks de inicialización y cambios son los más fundamentales y utilizados en el desarrollo diario con Angular. Estos nos permiten reaccionar a los momentos clave del ciclo de vida del componente y ejecutar la lógica necesaria en el momento adecuado.

ngOnInit - Inicialización del componente

El hook ngOnInit se ejecuta una sola vez después de que Angular haya inicializado las propiedades del componente. Es el lugar ideal para realizar tareas de configuración inicial como cargar datos, configurar suscripciones o inicializar variables.

Para usar ngOnInit, debemos implementar la interfaz OnInit e importarla desde @angular/core:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-usuario',
  template: `
    <div>
      <h2>{{ titulo }}</h2>
      <p>Usuario: {{ nombreUsuario }}</p>
    </div>
  `
})
export class UsuarioComponent implements OnInit {
  titulo = '';
  nombreUsuario = '';

  ngOnInit() {
    // Se ejecuta después de la inicialización del componente
    this.titulo = 'Panel de Usuario';
    this.cargarDatosUsuario();
  }

  private cargarDatosUsuario() {
    // Simular carga de datos
    this.nombreUsuario = 'Ana García';
  }
}

El método ngOnInit es especialmente útil para operaciones asíncronas como peticiones HTTP o configuración de temporizadores:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-productos',
  template: `
    <div>
      @if (cargando) {
        <p>Cargando productos...</p>
      } @else {
        <ul>
          @for (producto of productos; track producto.id) {
            <li>{{ producto.nombre }}</li>
          }
        </ul>
      }
    </div>
  `
})
export class ProductosComponent implements OnInit {
  productos: any[] = [];
  cargando = true;

  ngOnInit() {
    // Simulamos una petición HTTP que tarda 2 segundos
    setTimeout(() => {
      this.productos = [
        { id: 1, nombre: 'Laptop' },
        { id: 2, nombre: 'Mouse' },
        { id: 3, nombre: 'Teclado' }
      ];
      this.cargando = false;
    }, 2000);
  }
}

ngOnChanges - Cambios en propiedades de entrada

El hook ngOnChanges se ejecuta cada vez que cambian las propiedades de entrada (@Input) del componente. Recibe un objeto SimpleChanges que contiene información sobre qué propiedades cambiaron, sus valores anteriores y actuales.

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-contador',
  template: `
    <div>
      <h3>Contador: {{ valor }}</h3>
      <p>{{ mensaje }}</p>
    </div>
  `
})
export class ContadorComponent implements OnChanges {
  @Input() valor = 0;
  mensaje = '';

  ngOnChanges(changes: SimpleChanges) {
    // Se ejecuta cada vez que cambia el valor de entrada
    if (changes['valor']) {
      const cambio = changes['valor'];
      const valorAnterior = cambio.previousValue;
      const valorActual = cambio.currentValue;
      
      if (!cambio.firstChange) {
        this.mensaje = `Cambió de ${valorAnterior} a ${valorActual}`;
      } else {
        this.mensaje = 'Valor inicial establecido';
      }
    }
  }
}

Un ejemplo práctico donde ngOnChanges es muy útil es cuando necesitamos procesar datos cada vez que cambian:

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-estadisticas',
  template: `
    <div>
      <h3>Estadísticas de Ventas</h3>
      <p>Total de ventas: {{ totalVentas }}</p>
      <p>Promedio: {{ promedio }}</p>
    </div>
  `
})
export class EstadisticasComponent implements OnChanges {
  @Input() ventas: number[] = [];
  
  totalVentas = 0;
  promedio = 0;

  ngOnChanges(changes: SimpleChanges) {
    if (changes['ventas'] && this.ventas.length > 0) {
      // Recalcular estadísticas cada vez que cambien las ventas
      this.calcularEstadisticas();
    }
  }

  private calcularEstadisticas() {
    this.totalVentas = this.ventas.reduce((sum, venta) => sum + venta, 0);
    this.promedio = this.totalVentas / this.ventas.length;
  }
}

ngDoCheck - Detección de cambios personalizada

El hook ngDoCheck se ejecuta en cada ciclo de detección de cambios de Angular. Es útil cuando necesitamos detectar cambios que Angular no puede detectar automáticamente, como modificaciones en objetos o arrays.

import { Component, Input, DoCheck } from '@angular/core';

@Component({
  selector: 'app-lista',
  template: `
    <div>
      <h3>Elementos: {{ items.length }}</h3>
      <p>Última actualización: {{ ultimaActualizacion }}</p>
    </div>
  `
})
export class ListaComponent implements DoCheck {
  @Input() items: string[] = [];
  
  ultimaActualizacion = '';
  longitudAnterior = 0;

  ngDoCheck() {
    // Verificar si cambió la longitud del array
    if (this.items.length !== this.longitudAnterior) {
      this.ultimaActualizacion = new Date().toLocaleTimeString();
      this.longitudAnterior = this.items.length;
    }
  }
}

Buenas prácticas con hooks de inicialización

  • Usar ngOnInit para configuración inicial: Colocar la lógica de inicialización en ngOnInit en lugar del constructor del componente.

  • Implementar las interfaces correspondientes: Siempre implementar OnInit, OnChanges o DoCheck para mejor tipado y claridad.

  • Evitar operaciones costosas en ngDoCheck: Este hook se ejecuta frecuentemente, por lo que debemos ser cuidadosos con operaciones que consuman muchos recursos.

Estos hooks de inicialización y cambios proporcionan el control preciso que necesitamos sobre el comportamiento de nuestros componentes, permitiéndonos ejecutar código en los momentos exactos cuando el componente se inicializa o cuando sus datos cambian.

Hooks de contenido y vista

Los hooks de contenido y vista se ejecutan después de que Angular haya procesado el contenido proyectado y la vista del componente. Estos hooks son especialmente útiles cuando necesitamos interactuar con elementos del DOM o realizar operaciones que requieren que la vista esté completamente renderizada.

ngAfterContentInit - Contenido proyectado inicializado

El hook ngAfterContentInit se ejecuta una sola vez después de que Angular haya proyectado el contenido externo en el componente mediante ng-content. Este hook es ideal para acceder a elementos del contenido proyectado o realizar configuraciones que dependan de ese contenido.

import { Component, AfterContentInit, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-tarjeta',
  template: `
    <div class="tarjeta">
      <div class="cabecera">
        <ng-content select="[slot=titulo]"></ng-content>
      </div>
      <div class="contenido">
        <ng-content></ng-content>
      </div>
    </div>
  `,
  styles: [`
    .tarjeta { border: 1px solid #ccc; padding: 16px; }
    .cabecera { font-weight: bold; margin-bottom: 8px; }
  `]
})
export class TarjetaComponent implements AfterContentInit {
  @ContentChild('titulo') tituloElement!: ElementRef;

  ngAfterContentInit() {
    // El contenido proyectado ya está disponible
    console.log('Contenido proyectado inicializado');
    
    if (this.tituloElement) {
      console.log('Título encontrado:', this.tituloElement.nativeElement.textContent);
    }
  }
}

Uso del componente:

@Component({
  selector: 'app-ejemplo',
  template: `
    <app-tarjeta>
      <h3 #titulo slot="titulo">Mi Título</h3>
      <p>Este es el contenido de la tarjeta.</p>
    </app-tarjeta>
  `
})
export class EjemploComponent { }

ngAfterContentChecked - Verificación del contenido

El hook ngAfterContentChecked se ejecuta después de cada verificación del contenido proyectado. Es útil para reaccionar a cambios en el contenido que se proyecta desde el componente padre.

import { Component, AfterContentChecked, ContentChildren, QueryList, ElementRef } from '@angular/core';

@Component({
  selector: 'app-lista-pestañas',
  template: `
    <div class="pestañas">
      <ng-content select="app-pestaña"></ng-content>
      <p>Total de pestañas: {{ totalPestañas }}</p>
    </div>
  `
})
export class ListaPestañasComponent implements AfterContentChecked {
  @ContentChildren('pestaña') pestañas!: QueryList<ElementRef>;
  totalPestañas = 0;

  ngAfterContentChecked() {
    // Se ejecuta cada vez que se verifica el contenido proyectado
    const nuevaCantidad = this.pestañas?.length || 0;
    if (this.totalPestañas !== nuevaCantidad) {
      this.totalPestañas = nuevaCantidad;
      console.log(`Pestañas actualizadas: ${this.totalPestañas}`);
    }
  }
}

ngAfterViewInit - Vista inicializada

El hook ngAfterViewInit se ejecuta una vez después de que Angular haya inicializado completamente la vista del componente y todas sus vistas hijas. Este es el momento ideal para acceder a elementos del DOM o inicializar bibliotecas de terceros que requieren el DOM completo.

import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-grafico',
  template: `
    <div>
      <h3>Gráfico de Ventas</h3>
      <canvas #grafico width="400" height="200"></canvas>
      <p>{{ estadoGrafico }}</p>
    </div>
  `
})
export class GraficoComponent implements AfterViewInit {
  @ViewChild('grafico') canvas!: ElementRef<HTMLCanvasElement>;
  estadoGrafico = 'Cargando...';

  ngAfterViewInit() {
    // La vista ya está completamente inicializada
    this.inicializarGrafico();
  }

  private inicializarGrafico() {
    const ctx = this.canvas.nativeElement.getContext('2d');
    if (ctx) {
      // Dibujar un gráfico simple
      ctx.fillStyle = '#007bff';
      ctx.fillRect(50, 50, 100, 80);
      ctx.fillStyle = '#28a745';
      ctx.fillRect(200, 30, 100, 100);
      
      this.estadoGrafico = 'Gráfico cargado correctamente';
    }
  }
}

ngAfterViewChecked - Verificación de la vista

El hook ngAfterViewChecked se ejecuta después de cada verificación de la vista del componente y sus vistas hijas. Es útil para reaccionar a cambios en la vista después de que Angular haya actualizado el DOM.

import { Component, AfterViewChecked, ViewChildren, QueryList, ElementRef } from '@angular/core';

@Component({
  selector: 'app-galeria',
  template: `
    <div class="galeria">
      <h3>Galería de Imágenes</h3>
      @for (imagen of imagenes; track imagen.id) {
        <img #imagenRef [src]="imagen.url" [alt]="imagen.titulo">
      }
      <p>Imágenes cargadas: {{ imagenesCargadas }}</p>
    </div>
  `,
  styles: [`
    .galeria img { width: 100px; height: 100px; margin: 4px; }
  `]
})
export class GaleriaComponent implements AfterViewChecked {
  @ViewChildren('imagenRef') imagenesElementos!: QueryList<ElementRef>;
  
  imagenes = [
    { id: 1, url: 'imagen1.jpg', titulo: 'Imagen 1' },
    { id: 2, url: 'imagen2.jpg', titulo: 'Imagen 2' }
  ];
  
  imagenesCargadas = 0;

  ngAfterViewChecked() {
    // Contar imágenes que están en el DOM
    const cantidadActual = this.imagenesElementos?.length || 0;
    if (this.imagenesCargadas !== cantidadActual) {
      this.imagenesCargadas = cantidadActual;
    }
  }

  agregarImagen() {
    const nuevaId = this.imagenes.length + 1;
    this.imagenes.push({
      id: nuevaId,
      url: `imagen${nuevaId}.jpg`,
      titulo: `Imagen ${nuevaId}`
    });
  }
}

Orden de ejecución de los hooks

Es importante entender el orden en que se ejecutan estos hooks para usarlos correctamente:

import { Component, OnInit, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked } from '@angular/core';

@Component({
  selector: 'app-orden-hooks',
  template: `
    <div>
      <h3>Orden de Ejecución de Hooks</h3>
      <ng-content></ng-content>
      <p>Revisa la consola para ver el orden</p>
    </div>
  `
})
export class OrdenHooksComponent implements OnInit, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked {
  
  ngOnInit() {
    console.log('1. ngOnInit');
  }

  ngAfterContentInit() {
    console.log('2. ngAfterContentInit');
  }

  ngAfterContentChecked() {
    console.log('3. ngAfterContentChecked');
  }

  ngAfterViewInit() {
    console.log('4. ngAfterViewInit');
  }

  ngAfterViewChecked() {
    console.log('5. ngAfterViewChecked');
  }
}

Cuándo usar cada hook

  • ngAfterContentInit: Para configurar o acceder al contenido proyectado una sola vez
  • ngAfterContentChecked: Para reaccionar a cambios en el contenido proyectado (usar con precaución)
  • ngAfterViewInit: Para acceder al DOM, inicializar bibliotecas externas o configurar elementos de la vista
  • ngAfterViewChecked: Para reaccionar a cambios en la vista después de la detección de cambios

Los hooks de contenido y vista son fundamentales para trabajar con elementos del DOM y contenido proyectado, permitiéndonos ejecutar código en el momento exacto cuando estos elementos están disponibles y listos para ser manipulados.

Alternativas modernas en Angular 21

Además de los hooks de ciclo de vida tradicionales, Angular 21 ofrece alternativas modernas para algunos casos de uso frecuentes. Estas nuevas APIs son funciones que se ejecutan en contextos específicos y ofrecen mayor flexibilidad.

afterNextRender - Operaciones DOM tras el primer renderizado

La función afterNextRender() se ejecuta una sola vez después del primer renderizado del componente. Es la alternativa moderna a ngAfterViewInit para operaciones que requieren acceso al DOM, especialmente útil en aplicaciones con SSR (Server-Side Rendering) ya que solo se ejecuta en el navegador:

import { Component, afterNextRender, ElementRef, viewChild } from '@angular/core';

@Component({
  selector: 'app-grafico',
  template: `<canvas #canvas width="400" height="200"></canvas>`
})
export class GraficoComponent {
  canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');

  constructor() {
    afterNextRender(() => {
      // Acceso seguro al DOM, solo se ejecuta en el navegador
      const ctx = this.canvas().nativeElement.getContext('2d');
      if (ctx) {
        ctx.fillStyle = '#007bff';
        ctx.fillRect(50, 50, 100, 80);
      }
    });
  }
}

afterEveryRender - Operaciones DOM tras cada renderizado

La función afterEveryRender() se ejecuta después de cada ciclo de renderizado. Es la alternativa a ngAfterViewChecked para operaciones DOM recurrentes:

import { Component, afterEveryRender, signal } from '@angular/core';

@Component({
  selector: 'app-medidor',
  template: `<div #contenido>{{ texto() }}</div>`
})
export class MedidorComponent {
  texto = signal('Hola Angular 21');

  constructor() {
    afterEveryRender(() => {
      console.log('Vista renderizada');
    });
  }
}

DestroyRef - Limpieza de recursos moderna

DestroyRef es una alternativa a ngOnDestroy que se inyecta y permite registrar callbacks de limpieza desde cualquier punto del código:

import { Component, inject, DestroyRef } from '@angular/core';
import { interval } from 'rxjs';

@Component({
  selector: 'app-temporizador',
  template: `<p>Temporizador activo</p>`
})
export class TemporizadorComponent {
  private destroyRef = inject(DestroyRef);

  constructor() {
    const subscription = interval(1000).subscribe(() => {
      console.log('Tick');
    });

    this.destroyRef.onDestroy(() => {
      subscription.unsubscribe();
      console.log('Suscripción cancelada');
    });
  }
}

DestroyRef es especialmente útil en servicios y funciones auxiliares donde no se tiene acceso al hook ngOnDestroy, y se integra perfectamente con takeUntilDestroyed() de @angular/core/rxjs-interop.

Cuándo usar cada alternativa

  • afterNextRender: Reemplaza ngAfterViewInit para inicialización de DOM en aplicaciones SSR
  • afterEveryRender: Reemplaza ngAfterViewChecked para operaciones DOM recurrentes
  • DestroyRef: Complementa o reemplaza ngOnDestroy para limpieza de recursos en cualquier contexto

Los hooks tradicionales siguen siendo completamente válidos y son la forma principal de gestionar el ciclo de vida. Las alternativas modernas son especialmente útiles en escenarios de SSR y cuando se necesita registrar limpieza desde funciones auxiliares o servicios.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Angular

Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Comprender qué son los hooks de ciclo de vida en Angular y su importancia. Aprender a usar los hooks de inicialización y cambios como ngOnInit, ngOnChanges y ngDoCheck. Conocer los hooks relacionados con el contenido proyectado y la vista: ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit y ngAfterViewChecked. Entender el orden de ejecución de los hooks y cuándo utilizar cada uno. Aplicar buenas prácticas para optimizar el uso de los hooks y evitar problemas de rendimiento.