Component Lifecycle Hooks (OnInit, OnDestroy)

Component Lifecycle Hooks (OnInit, OnDestroy)

In Angular applications, components are the fundamental building blocks for constructing user interfaces. Unlike native JavaScript, Angular provides developers with precise control over the creation, update, and destruction processes of components through its declarative lifecycle management mechanism. Among these, OnInit (initialization) and OnDestroy (cleanup) are two of the most foundational and critical lifecycle hooks. Mastering the usage scenarios of these two hooks is a key prerequisite for writing high-performance Angular applications with minimal risk of memory leaks.
When Angular creates a new component instance, it first invokes the component's constructor, followed immediately by the method within the OnInit interface. This marks the starting point of the component lifecycle and is typically used to complete all preparatory work related to data fetching and initialization. Within OnInit, developers should focus on "setup" tasks, ensuring that the component is in a stable and complete state before rendering to the user.

Common application scenarios include:

  • Subscribing to external services: Initiating HTTP requests to load initial data (such as from APIs or local storage).
  • Registering event listeners: Binding events to DOM elements or registering callback functions at the global window/document level.
  • Configuring dependencies: Initializing parameters or state objects required by third-party libraries.

It is important to note that the OnInit method is executed only once, specifically when the component is first created. If an asynchronous request initiated in OnInit has not yet completed (e.g., data has not finished loading), Angular will not immediately invoke subsequent hooks (such as ngAfterViewInit). Attempting to access DOM elements at this stage may result in runtime errors or unpredictable behavior. Therefore, when writing code, adhere to the principle of "initialize before rendering," ensuring that all dependent data is ready.

OnDestroy: Resource Cleanup and Memory Management

As a component is removed from the view or destroyed, Angular triggers the OnDestroy hook. The sole and most important task during this phase is the release and cleanup of resources. Ignoring this step can lead to severe memory leak issues, particularly in applications with long-running processes or frequent page route switches.

Key items to handle within OnDestroy include:

  • Unsubscribing: If Observables or Promises were created via RxJS or other libraries during the component lifecycle, you must call the .unsubscribe() method upon destruction to stop subsequent polling, timers, or network requests.
  • Removing event listeners: Unbind DOM element events or global callback functions registered in OnInit to prevent them from continuing to occupy memory and execute invalid logic after the page is unloaded.
  • Cleaning up temporary state: Clear cache data maintained internally by the component or other variables that should only exist within the lifecycle of the component.

Below is a typical code snippet for resource management:

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

@Component({
  selector: 'app-example',
  template: `<p>Component content</p>`
})
export class ExampleComponent implements OnInit, OnDestroy {
  private subscription?: Subscription;

  ngOnInit() {
    // Initiate data request and subscribe to the response stream
    this.subscription = new Subscription();
    
    const observable$ = someApiService.getDataStream();
    this.subscription.add(observable$.subscribe(data => {
      console.log('Received new data:', data);
    }));
  }

  ngOnDestroy() {
    // Must unsubscribe to prevent memory leaks
    if (this.subscription) {
      this.unsubscribeAll(this.subscription);
    }
  }

  private unsubscribeAll(subscription: Subscription): void {
    subscription.unsubscribe();
  }
}

As demonstrated in the example above, OnDestroy serves as the critical defense line against resource accumulation. Developers must develop the habit of actively cleaning up all dynamically created resources upon component destruction, regardless of whether those resources are still being used. This defensive programming mindset not only enhances application stability but also optimizes runtime efficiency in complex scenarios.