What Are Lifecycle Hooks?

Every Angular component goes through a well-defined lifecycle — from creation to destruction. Angular exposes key moments in this lifecycle through lifecycle hooks: special methods you can implement in your component class to run logic at the right time.

Understanding lifecycle hooks is essential for managing subscriptions, fetching data at the right moment, and avoiding common memory leaks.

The Complete Lifecycle Hook Sequence

Angular calls these hooks in the following order:

  1. ngOnChanges
  2. ngOnInit
  3. ngDoCheck
  4. ngAfterContentInit
  5. ngAfterContentChecked
  6. ngAfterViewInit
  7. ngAfterViewChecked
  8. ngOnDestroy

The Most Important Hooks

ngOnInit

This is the most commonly used hook. It runs once after the component's input properties have been initialized. Use it to fetch data from a service, set up subscriptions, or initialize component state.

export class UserProfileComponent implements OnInit {
  user: User;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.userService.getUser(1).subscribe(data => this.user = data);
  }
}

Why not use the constructor? The constructor is for dependency injection only. Angular hasn't processed input bindings yet at that point, so ngOnInit is the correct place for initialization logic.

ngOnChanges

Called before ngOnInit and every time an @Input() property changes. It receives a SimpleChanges object that describes what changed.

ngOnChanges(changes: SimpleChanges): void {
  if (changes['userId']) {
    this.loadUserData(changes['userId'].currentValue);
  }
}

Use this hook when your component needs to react to parent-driven data changes.

ngAfterViewInit

Runs once after Angular has fully initialized the component's view and child views. This is the correct place to interact with child components or DOM elements referenced via @ViewChild.

@ViewChild('chartCanvas') chartCanvas: ElementRef;

ngAfterViewInit(): void {
  this.renderChart(this.chartCanvas.nativeElement);
}

ngOnDestroy

Called just before Angular destroys the component. This is critical for cleanup: unsubscribe from Observables, clear timers, and detach event listeners to prevent memory leaks.

private destroy$ = new Subject<void>();

ngOnInit(): void {
  this.dataService.stream$
    .pipe(takeUntil(this.destroy$))
    .subscribe(data => this.data = data);
}

ngOnDestroy(): void {
  this.destroy$.next();
  this.destroy$.complete();
}

Quick Reference Table

Hook When It Runs Common Use Cases
ngOnChanges On every @Input change React to parent data updates
ngOnInit Once, after first ngOnChanges Data fetching, subscriptions
ngAfterViewInit Once, after view renders DOM access, third-party libs
ngOnDestroy Before component is removed Cleanup subscriptions, timers

Best Practices

  • Always implement the corresponding interface (e.g., implements OnInit) — it provides type safety and IDE autocompletion.
  • Keep hook logic focused — extract heavy logic into private methods or services.
  • Never skip ngOnDestroy cleanup when working with long-lived Observables.
  • Avoid triggering side effects inside ngDoCheck — it runs on every change detection cycle and can seriously hurt performance.