Setters vs ngOnChanges: which one is better?

·
·3 min read
Cover Image for Setters vs ngOnChanges: which one is better?

Getting notified about an Angular component's property changes is normally done in 2 ways:

  • adding a setter to the property
  • using the ngOnChanges lifecycle hook

But... is there a best practice?

This discussion recently came up with my colleagues while trying to establish a standard practice in our codebase. We tried to find objective arguments to understand which one is better.

As usual, the answer depends on the scenario.

Style

Style is very much a subjective factor, but using a setter is hands-down my favorite approach. Let's take a look at a common scenario:

class MyComponent {
  private subject$ = new Subject<string>();

  @Input()
  set name(name: string) {
    this.subject$.next(name);
  }
}

It's succinct, type-safe, and encourages the usage of Observables. Not much to dislike, imho.

But can you not add a getter?

Yes. It turns out, Angular does not check the previous value by invoking the getter on the property, but stores its value in its component's logical view.

If you're interested in reading the source code where this happens, check this out.

class MyComponent implements OnChanges {
  @Input() name: string;

  private subject$ = new Subject<string>();

  ngOnChanges(changes: SimpleChanges) {
    // changes.name.currentValue is typed as `any`
    this.subject$.next(changes.name.currentValue);
  }
}

The ngOnChanges lifecycle hook, on the contrary, it's not as nice (in my opinion) - and most importantly, is weakly typed.

Also - it's worth to mention that using setters usually takes less code, which is always a good thing.

Performance

Does performance change much? At first, we thought that ngOnChanges would be more efficient as being part of Angular's lifecycle hooks, and therefore being aware of when a property changed.

It turns out, though, that Angular does only change a property when the binding is a new instance. Of course, we're taking into account the change detection being OnPush.

Performance-wise, according to my tests, there isn't a better way, and shouldn't be a factor when deciding which way to go with.

Dealing with multiple Inputs

The situation changes when taking into account changes on multiple inputs:

class MyComponent implements OnChanges {
  @Input() name: string;
  @Input() email: string;

  private username$ = new Subject<string>();

  ngOnChanges({ name, email }: SimpleChanges) {
    const username = name.currentValue || email.currentValue;
    this.username$.next(username);
  }
}

In this case, it's fairly straightforward and simpler to receive all the inputs at once.

But because this situation is pretty uncommon, and sometimes a sign of a code-smell, you'll find yourselves wanting to use the setter the majority of the time.

At the end of the day, remember that this decision is always up to you and your team's preferences.

Thank you for reading, I hope you enjoyed this article. If you did, consider follow me on Twitter or sign up to the Newsletter using the form below!


Learn more about
AngularAngular

Cover Image for Benchmarking Angular 12 with Webpack 5
·2 min read·
AngularAngular

Angular 12 has been released and with it the much awaited Webpack 5 upgrade. In this post I benchmarked the bundle-size and compilation speed against the previous version

Cover Image for Principles for creating libraries with Nx and Angular
·5 min read·
AngularAngular

Working with Nx may be confusing. This article explains how I create Nx libraries and the principles behind my motivations

Cover Image for Where to put your Angular models?
·3 min read·
AngularAngular

Organizing entities and models in your Angular app may be hard. This article explains where to put your entities and what mistakes to watch out for

Cover Image for Using the Intersection Observer API with Angular
·5 min read·
AngularAngular

This article shows how to build a directive with Angular that uses the Intersection Observer API to check when an element becomes visible on the page

Cover Image for Async Rendering with a single Rx Operator
·3 min read·
AngularAngular

Increase your app rendering performance with this simple Rx operator

Cover Image for 3 Ways to Render Large Lists in Angular
·6 min read·
AngularAngular

An overview of the available techniques to render large lists of items with Angular