It is possible with Angular components to see how their state evolves from birth to destruction. Lifecycle hooks in Angular are procedures that you can use to "hook" into various stages and events at run time. They help you to have a robust finished product which is easy to construct by enabling quick fixes. Whether you are initializing data, responding to changes or tidying up resources, lifecycle hooks make it possible for you to develop productive, manageable applications
When you build a house, we can say that the ground must be prepared prior to any structures being laid atop it. Water and electricity are brought into new homes, the same for plumbing or even ceramics. Paint and furniture then go on finally after all that. As shown, each step of the construction process takes place at a certain time and in specific detail; leaving out one step may very likely lead to confusion.
In Angular, lifecycle hooks work just like that. They give you the opportunity to add code, component by component, and custom logic hooking into key moments in a component's life. From creation—when something is born out of nothing in your browser window—until destruction, when it is no more than memory dust on some computer system miles away, lifecycle hooks play a crucial role.
This can be done at any point during construction: whether you’re fetching data from APIs, managing subscriptions for user input handlers to avoid memory crashes, or cleaning up resources after a component is destroyed.
In this blog post, we’ll delve into Angular’s lifecycle hooks and provide practical examples, as well as best practices. By the end of this article, you can become an expert on these key points in your Angular application that most developers overlook: the lifecycle.
Let’s get started!
What Are Angular Lifecycle Hooks?
Angular components and directives have a well-defined lifecycle managed by Angular itself. Lifecycle hooks are methods that you can redefine in order to execute logic at specific points in a component’s lifecycle.
Some examples include:
- When a component is initialized.
- When its input properties change or output events are fired.
- When it’s destroyed and removed from the DOM.
These hooks are particularly useful for tasks like:
- Fetching data from an API.
- Responding to user interactions.
- Managing subscriptions to prevent memory leaks.
- Cleaning up resources when the component is destroyed.
- ngOnChanges: Responds to input changes.
- ngOnInit: Initializes component data.
- ngDoCheck: Detects custom changes.
- ngAfterContentInit: Runs after content projection.
- ngAfterContentChecked: Checks projected content.
- ngAfterViewInit: Runs after the view renders.
- ngAfterViewChecked: Checks view changes.
- ngOnDestroy: Cleans up before component destruction.
Mastering Angular's Eight Lifecycle Hooks
- When it runs: Before ngOnInit and whenever an input property changes
- Use case: Reacting to changes in input properties.
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({ selector: 'app-user', template: `<p>User Name: {{ name }}</p>`,})export class UserComponent implements OnChanges { @Input() name: string = '';
ngOnChanges(changes: SimpleChanges) { if (changes['name']) { console.log(`Name changed from ${changes['name'].previousValue} to ${changes['name'].currentValue}`); } }}
- When It Runs : Once, after the first ngOnChanges.
- Use Case : Initializing data, fetching data from APIs, or setting up subscriptions.
import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-dashboard', template: `<h1>Welcome to the Dashboard</h1>`,})export class DashboardComponent implements OnInit { ngOnInit() { console.log('Dashboard initialized'); // Fetch data or initialize services here }}
- When It Runs : During every change detection cycle.
- Use Case : Custom change detection logic (use sparingly, as it can impact performance).
import { Component, DoCheck } from '@angular/core';
@Component({ selector: 'app-custom-check', template: `<p>Custom Change Detection</p>`,})export class CustomCheckComponent implements DoCheck { ngDoCheck() { console.log('Change detected!'); }}
- When It Runs : After Angular projects external content into the component’s view.
- Use Case : Working with content projected via <ng-content>.
import { Component, AfterContentInit } from '@angular/core';
@Component({ selector: 'app-content', template: `<ng-content></ng-content>`,})export class ContentComponent implements AfterContentInit { ngAfterContentInit() { console.log('Content has been initialized'); }}
5.ngAfterContentChecked
- When it runs: After Angular checks the content projected into the component.
- Use case: Performing actions after content changes.
Example:
import { Component, AfterContentChecked } from '@angular/core';
@Component({
selector: 'app-content-checked',
template: `<p>Content Checked</p>`,
})
export class ContentCheckedComponent implements AfterContentChecked {
ngAfterContentChecked() {
console.log('Content checked');
}
}
6.ngAfterViewInit
- When it runs: After Angular initializes the component's views and child views.
- Use case: Manipulating the DOM or initializing third-party libraries.
Example:
import { Component, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-view',
template: `<p>view initialized</p>`
})
export class ViewComponent implements AfterViewInit {
ngAfterViewInit() {
console.log('View has been initialized');
}
}
7.ngAfterViewChecked
- When It Runs: After Angular checks the component’s views and child views.
- Use Case: Performing actions after view changes.
Example:
import { Component, AfterViewChecked } from '@angular/core';
@Component({
selector: 'app-view-checked',
template: '`<p>viewChecked</p>`'
})
export class ViewCheckedComponent implements AfterViewChecked {
ngAfterViewChecked() {
console.log('View checked');
}
}
8.ngOnDestroy()
- When It Runs: Just before Angular destroys the component.
- Use Case: Cleaning up resources like subscriptions or timers.
Example:
import { Component, OnDestroy } from '@angular/core';
@Component({
selector: 'app-timer',
template: '`<p>timer running</p>`'
})
export class TimerComponent implements OnDestroy {
intervalId: any;
constructor() {
this.intervalId = setInterval(() => console.log('Tick'), 1000);
}
ngOnDestroy() {
clearInterval(this.intervalId);
console.log('Timer destroyed');
}
}
Step-by-Step Example: Using Lifecycle Hooks Together
Let’s combine multiple lifecycle hooks in a single example to demonstrate their flow:
import { Component, OnInit, OnDestroy, OnChanges, SimpleChanges, Input } from '@angular/core';
@Component({
selector: 'app-lifecycle-demo',
template: `
<p>Name: {{ name }}</p>
<button (click)="changeName()">Change Name</button>
`
})
export class LifecycleDemoComponent implements OnInit, OnDestroy, OnChanges {
@Input() name: string = 'John';
ngOnInit() {
console.log('Component initialized');
}
ngOnChanges(changes: SimpleChanges) {
console.log('Name changed:', changes['name']);
}
ngOnDestroy() {
console.log('Component destroyed');
}
changeName() {
this.name = 'Jane';
}
}
Best Practices for Using Lifecycle Hooks
- Avoid Heavy Logic in ngOnChanges: Since this hook runs frequently, keep its logic lightweight to avoid performance issues.
- Clean Up Resources in ngOnDestroy: Always unsubscribe from observables and clear timers to prevent memory leaks.
- Use ngOnInit for Initialization: Avoid placing initialization logic in the constructor; use ngOnInit instead.
- Minimize Use of ngDoCheck: This hook runs often and can slow down your app if overused.
- Leverage ngAfterViewInit for DOM Manipulation: If you need to interact with the DOM, do it here to ensure the view is fully initialized.
With a strong understanding of these hooks and by making full use of them, you can build dynamic, efficient, and maintainable applications.
To sum up:
- Angular has eight lifecycle hooks, each corresponding to a specific function.
- Use ngOnInit for initialization, and ngOnDestroy when you want to clean up everything.
- Pay attention to performance when using hooks such as ngDoCheck and ngOnChanges.
- Adopt best practices to write clean, efficient, and maintainable code.
Start playing around with lifecycle hooks today, and see how much more robust your Angular applications become thanks to them!
No comments