Lifecycle Hooks In Angular and When To Use Them

Lifecycle Hooks In Angular and When To Use Them

Introduction

Angular provides lifecycle hooks that allow developers to execute logic at specific moments in a component’s lifecycle. Understanding these hooks is crucial for writing efficient, optimized, and well-structured Angular applications. In this article, we will explore each lifecycle hook in detail, discuss its purpose, and provide real-world scenarios where each can be applied.


Angular Component Lifecycle Overview

Angular components go through a series of lifecycle events from initialization to destruction. The lifecycle consists of the following hooks, in order of execution:

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

Each of these hooks serves a specific purpose and is called at a particular phase of the component’s lifecycle.


1. ngOnChanges(changes: SimpleChanges)

Triggered: Before ngOnInit(), and whenever an @Input() property changes.

Use Cases:

  • Detecting changes in @Input() properties from the parent component.
  • Reacting to input changes by fetching new data or modifying component behavior.

Example:

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

@Component({
  selector: 'app-child',
  template: `<p>Data: {{ data }}</p>`
})
export class ChildComponent implements OnChanges {
  @Input() data: string;

  ngOnChanges(changes: SimpleChanges) {
    if (changes['data']) {
      console.log('data changed:', changes['data'].currentValue);
    }
  }
}

2. ngOnInit()

Triggered: Once after the first ngOnChanges(), when the component is initialized.

Use Cases:

  • Performing component initialization logic.
  • Fetching initial data from an API.
  • Setting up subscriptions or event listeners.

Example:

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

@Component({
  selector: 'app-example',
  template: `<p>Data loaded: {{ data }}</p>`
})
export class ExampleComponent implements OnInit {
  data: string;

  ngOnInit() {
    this.data = 'Fetching initial data...';
  }
}

3. ngDoCheck()

Triggered: During every change detection cycle, even if @Input() properties do not change.

Use Cases:

  • Implementing custom change detection logic.
  • Detecting deep object changes.

Example:

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

@Component({
  selector: 'app-check',
  template: `<p>Check count: {{ count }}</p>`
})
export class CheckComponent implements DoCheck {
  count = 0;

  ngDoCheck() {
    this.count++;
    console.log('Change detection triggered', this.count);
  }
}

4. ngAfterContentInit()

Triggered: Once after Angular projects external content into the component.

Use Cases:

  • Running logic when projected content (e.g., <ng-content>) is initialized.

Example:

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

@Component({
  selector: 'app-content',
  template: `<ng-content></ng-content>`
})
export class ContentComponent implements AfterContentInit {
  ngAfterContentInit() {
    console.log('Projected content initialized');
  }
}

5. ngAfterContentChecked()

Triggered: After ngAfterContentInit() and every subsequent change detection cycle.

Use Cases:

  • Responding to changes in projected content.

Example:

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

@Component({
  selector: 'app-content-check',
  template: `<ng-content></ng-content>`
})
export class ContentCheckComponent implements AfterContentChecked {
  ngAfterContentChecked() {
    console.log('Projected content checked');
  }
}

6. ngAfterViewInit()

Triggered: Once after the component’s view (including child components) is initialized.

Use Cases:

  • Interacting with child components using @ViewChild().
  • Initializing third-party libraries that depend on the DOM.

Example:

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

@Component({
  selector: 'app-view',
  template: `<div #myElement>Hello World</div>`
})
export class ViewComponent implements AfterViewInit {
  @ViewChild('myElement') myElement: ElementRef;

  ngAfterViewInit() {
    console.log('View initialized', this.myElement.nativeElement);
  }
}

7. ngAfterViewChecked()

Triggered: After ngAfterViewInit() and every subsequent change detection cycle.

Use Cases:

  • Performing operations that require the view to be fully rendered.

Example:

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

@Component({
  selector: 'app-view-check',
  template: `<p>View Checked</p>`
})
export class ViewCheckComponent implements AfterViewChecked {
  ngAfterViewChecked() {
    console.log('View checked');
  }
}

8. ngOnDestroy()

Triggered: Just before the component is destroyed.

Use Cases:

  • Unsubscribing from observables.
  • Cleaning up event listeners.

Example:

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

@Component({
  selector: 'app-destroy',
  template: `<p>Destroy example</p>`
})
export class DestroyComponent implements OnDestroy {
  ngOnDestroy() {
    console.log('Component is being destroyed');
  }
}

Conclusion

Understanding Angular lifecycle hooks helps developers write efficient and bug-free applications. Properly using these hooks allows for optimized data fetching, memory management, and event handling. By leveraging these hooks effectively, developers can improve application performance and maintainability.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top