0%

angular-change-detection-on-push

Introduction

In this article, we will learn how to use ChangeDetectionStrategy.OnPush in Angular to improve the performance of your application. By default, Angular uses ChangeDetectionStrategy.Default, which means that the change detection runs every time an event is triggered in the application. This can be inefficient if your application has a lot of components that don’t need to be updated every time an event is triggered. By using ChangeDetectionStrategy.OnPush, you can tell Angular to only run change detection on a component when its input properties change. with onPush strategy, Angular will only trigger change detection in the following cases:

  • When component’s input property changes
  • When an event is triggered in the component
  • When you manually trigger change detection
  • 注意:这里好像还有一条是async pipe,但是我找不到文档了,以后找到再补充吧。

Example

Take a look at the product component below, it has an input property name, and an event handler which changes the price of the product. We have set the changeDetection property to ChangeDetectionStrategy.OnPush in the component’s metadata.

1
2
3
4
<!-- product.component.html -->
<button (click)="changePrice(10)">Change price</button>
<p>Product Name: {{name}}</p>
<p>Product Price: {{price}}</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component({
selector: 'app-product',
standalone: true,
imports: [],
templateUrl: './product.component.html',
styleUrl: './product.component.css',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductComponent implements OnInit, DoCheck, OnChanges {
@Input() name: string;
price: number;

constructor() {
this.name = '';
this.price = 0;
}

// `ngDoCheck()` will called each time change detection run
ngDoCheck() {
console.log('change detection triggered...')
}

// This will not trigger change detection
ngOnInit() {
setTimeout(() => {
this.price = 20;
}, 1000);
}

// click handler, will trigger change detection.
changePrice(price: number) {
this.price = price;
}
}
  1. When parent component change the input property name, Angular will trigger change detection in the product component. and console will output change detection triggered...
  2. When user click button to change the price, Angular will trigger change detection in the product component. and console will output change detection triggered...
  3. setTimeout function will not trigger change detection in the product component.

Change Detection with OnPush Diagram

See here for details.

Do I need OnPush strategy if component has no @Input bindings?

Yes, OnPush still make sense even if the component has no @Input bindings.

  1. With OnPush, change detection still triggers when an event is triggered in the component.
  2. With OnPush, you prevent the change detection running automatically when the parent component changes.
  3. With OnPush, you can manually trigger change detection when needed with ChangeDetectorRef.detectChanges(), or ChangeDetectorRef.markForCheck().

OnPush + signal is the future of Angular.

References:

  1. https://angular.dev/best-practices/skipping-subtrees
  2. https://v17.angular.io/guide/change-detection-skipping-subtrees