Are you curious about how ngOnChanges works and when to use it?
Well, then you've come to the right place!
In this comprehensive guide to Angular's ngOnChanges lifecycle hook, we'll explore how it works and why it's important, and I’ll explain how to use it effectively in your Angular applications.
I’ll even compare it against some other lifecycle hooks so that by the end of this guide, you'll feel far more confident in using ngOnChanges to make your components more robust and responsive.
So grab a coffee and a notepad and let's dive in!
Sidenote: If you want to dive deeper into Angular, as well as all of its lifecycle changes, and more, then check out my complete Angular Developer course.
Fully updated and covering the latest Angular features for 2025, I guarantee that this is the most comprehensive online course on Angular.
You’ll also build confidence by creating real-world projects (including a massive video-sharing application similar to the example in this guide) step-by-step alongside me, Senior Developer!
With that out of the way, let’s get into the guide!
ngOnChanges is one of the multiple lifecycle hooks available in Angular.
This particular hook gets called when any data-bound input property changes. It then notifies you when an input property changes and provides the current and previous values, allowing you to understand and react to these changes effectively.
For example
Suppose you have an interface component displaying a user's profile information.
 
If the user updates their profile picture, Angular detects this change and triggers ngOnChanges.
 
(Fun fact - Netflix was built on Angular).
And so within the ngOnChanges function, you can write code to update the displayed picture, ensuring that the user sees their new profile image instantly.
This also makes it versatile for updating UI in sync with state and logging changes for debugging purposes!
So now we know what ngOnChanges is and how it works, let's look at how to use it.
To use ngOnChanges, you just need to implement the OnChanges interface in your component and define the ngOnChanges method.
(This method takes one argument, such as an object adhering to the SimpleChanges interface, that contains the current and previous property values for each changed input property).
For example
Here's a basic implementation:
import { OnChanges, SimpleChanges } from '@angular/core';
@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnChanges {
  @Input() data: any;
  ngOnChanges(changes: SimpleChanges) {
    for (let propName in changes) {
      let change = changes[propName];
      let curVal = JSON.stringify(change.currentValue);
      let prevVal = JSON.stringify(change.previousValue);
      console.log(`${propName}: currentValue = ${curVal}, previousValue = ${prevVal}`);
    }
  }
}What's happening here?
Well, in the ProfileComponent, we have a single @Input() property called name.
And so if the parent component changes the name, Angular calls the ngOnChanges method with a SimpleChanges object.
For example
If you were to change the name from 'John' to the name of our glorious leader 'Bruno', then the ngOnChanges method logs the following message:
name: currentValue = "Bruno", previousValue = "John"It’s a little complicated in that ngOnChanges is called both before and after change detection, depending on the context.
Angular calls ngOnChanges at two specific points:
ngOnInit and after the first ngOnCheckFor example
When a component is first being created, Angular goes through the following sequence of lifecycle hooks:
ngOnInitngOnChanges. At this point, the component is fully initializedngOnInit and then every subsequent check of the componentThis means that after the component is fully initialized and whenever Angular's change detection runs, it checks for changes in the values of properties and bindings. If it detects changes, it updates the view to match the current state of the component and then triggers ngOnChanges.
So like I said, in a way, ngOnChanges can come both before and after change detection.
We mentioned a few of the other lifecycle hooks above, so let’s look at a few and compare them to ngOnChanges.
ngOnChanges is called before ngOnInit during the component initialization phase. After that, ngOnChanges is called every time an input property changes, while ngOnInit is only called once.ngOnInit is used for component initialization work, like calling a service to fetch data. ngOnChanges is used to perform actions in response to input property changes.For example: Using ngOnInit for initialization
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
@Component({
  selector: 'app-data-fetcher',
  template: `<div>{{ data }}</div>`
})
export class DataFetcherComponent implements OnInit {
  data: string;
  constructor(private dataService: DataService) {}
  ngOnInit() {
    this.dataService.fetchData().subscribe(fetchedData => {
      this.data = fetchedData;
    });
  }
}For example: Using ngOnChanges to react to input changes
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
  selector: 'app-user-profile',
  template: `<h2>{{ user.name }}</h2>`
})
export class UserProfileComponent implements OnChanges {
  @Input() user: { name: string, age: number };
  ngOnChanges(changes: SimpleChanges) {
    if (changes['user']) {
      const currentValue = changes['user'].currentValue;
      const previousValue = changes['user'].previousValue;
      console.log('User changed from', previousValue, 'to', currentValue);
    }
  }
}For example: Using ngDoCheck for custom change detection
import { Component, DoCheck, Input, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
@Component({
  selector: 'app-settings',
  template: `<div>Settings for {{ settings.theme }}</div>`
})
export class SettingsComponent implements DoCheck {
  @Input() settings: { theme: string, notifications: boolean };
  private differ: KeyValueDiffer<string, any>;
  constructor(private differs: KeyValueDiffers) {
    this.differ = this.differs.find({}).create();
  }
  ngDoCheck() {
    const changes = this.differ.diff(this.settings);
    if (changes) {
      changes.forEachChangedItem(item => {
        console.log('Changed item:', item.key, 'currentValue:', item.currentValue, 'previousValue:', item.previousValue);
      });
    }
  }
}ngOnChanges to react to changes in input properties that may occur multiple times. If your component receives multiple input properties and requires complex calculations whenever any of these properties change, ngOnChanges is preferablengOnInit for initialization logic that relies on set input properties and needs to run once per component instantiationngDoCheck when you want to perform an action during every change detection cycle, regardless of whether any changes were detectedAs you can see, using ngOnChanges can be incredibly useful for detecting and reacting to changes in input properties.
However, for simpler or more performance-sensitive scenarios, then other Angular features might be more appropriate.
For properties that change very frequently (e.g., every few milliseconds), using ngOnChanges can lead to performance issues due to the high frequency of method calls.
Instead, consider using RxJS observables with the async pipe in your templates. This approach can be more efficient because Angular's change detection can be more finely controlled and optimized.
import { Component, Input, OnInit } from '@angular/core';
import { Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
  selector: 'app-stock-ticker',
  template: `<div>Current Price: {{ price$ | async }}</div>`
})
export class StockTickerComponent {
  @Input() stockSymbol: string;
  price$: Observable<number>;
  ngOnInit() {
    this.price$ = interval(1000).pipe(
      map(() => this.fetchStockPrice(this.stockSymbol))
    );
  }
  fetchStockPrice(symbol: string): number {
    // Simulate fetching stock price
    return Math.random() * 100 + 100;
  }
}For simple scenarios where you need to react to changes in input properties to compute a value or trigger a side effect, using a getter and setter for the input property might be sufficient and more straightforward than implementing ngOnChanges.
This approach allows you to handle changes immediately in the setter method.
private _inputValue: string;
@Input()
set inputValue(value: string) {
  this._inputValue = value;
  this.doSomething(value);
}
get inputValue(): string {
  return this._inputValue;
}
doSomething(value: string) {
  // React to the change
  console.log('Input value changed to', value);
}Hopefully this guide has opened up your eyes to some possibilities of how you might use this hook in your own projects.
Getting a handle on the ngOnChanges lifecycle hook in Angular is key for making your apps more dynamic and responsive.
By getting comfortable with ngOnChanges and other Angular hooks, you'll be able to make your apps faster and more efficient!
Remember, if you want to dive deeper into Angular and have a structured learning process that can take you from complete beginner to getting hired, then check out my complete Angular Developer course.
Want a sneak peak?
I went ahead and uploaded the first 4 hours of the course below for free:
Once you join, you’ll also have access to every other course in the Zero To Mastery library, as well as access to the private Discord.
You can ask questions from me, as well as chat with fellow students and working Angular Developers!
Check out some of my other Angular articles, guides and cheatsheets!
