Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

changeDetection: ChangeDetectionStrategy.OnPush doesn't seem to be working?

https://stackblitz.com/edit/angular-xpamld

Question: Can someone help me understand why my prototype's changeDetection: ChangeDetectionStrategy.OnPush still allows me to update the inner value name? If this is not what ChangeDetectionStrategy.OnPush suppose to prevent, what should it be doing?

app.component.ts:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent  {
  public name = 'Angular 5';
  public changeName() {
    this.name = 'Outer';
  }
}

app.component.html:

<hello name="{{ name }}"></hello>
<button (click)="changeName()">Outter Change</button>
<p>{{name}}-- outer</p>
<p>
  Start editing to see some magic happen :)
</p>

hello.component.ts:

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1> <button (click)="changeName()">inner Change</button>`,
  styles: [`h1 { font-family: Lato; }`],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloComponent  {
  @Input() name: string;


  public changeName() {
    this.name = 'Inner';
  }
}
like image 845
Armeen Harwood Avatar asked Feb 04 '18 07:02

Armeen Harwood


People also ask

What triggers OnPush change detection?

But with OnPush strategy, the change detector is only triggered if the data passed on @Input() has a new reference. This is why using immutable objects is preferred, because immutable objects can be modified only by creating a new object reference.

What is the difference between OnPush and default change detection?

OnPush means that the change detector's mode will be set to CheckOnce during hydration. Default means that the change detector's mode will be set to CheckAlways during hydration.

How do you stop change detection?

Go to Inventory>>Devices. Select the devices in which you want to enable/disable change detection.

What is Changedetectionstrategy in Angular?

Introduction. By default, Angular 2+ performs change detection on all components (from top to bottom) every time something changes in your app. A change can occur from a user event or data received from a network request.


2 Answers

Because primitive datatype is immutable - if you change it, its reference also changes, so ChangeDetectorRefof your component knows it must detect changes (because OnPush looks for references changes, not data mutations in arrays, objects). If you want to avoid that on primitives, you can manually deactivate/activate this on ChangeDetectorRef instance with detach()/ reattach():

import { ChangeDetectorRef } from '@angular/core';

export class HelloComponent  {
  @Input() name: string;

 constructor(private ref: ChangeDetectorRef) {}

  public changeName() {
    this.ref.detach();
    this.name = 'Inner';
  }
}
like image 89
Julius Dzidzevičius Avatar answered Sep 22 '22 13:09

Julius Dzidzevičius


The default change detection strategy is to be conservative and check all its bindings for something that might have changed. Typically, a change detection cycle is triggered whenever an [input] changes, or an (event) occurs from any component.

By changing a component's change detection strategy to OnPush, Angular only checks for updates when the component's inputs have actually changed. This allows Angular to be more efficient with change detection by allowing entire sub-trees to be skipped during change detection.

Here is a good article on it: https://vsavkin.com/immutability-vs-encapsulation-90549ab74487

Some points to help with the understanding is:

  1. By default, when a change detection digest is triggered, all bindings are checked for updates from all components, regardless of where the change originally came from.
  2. Change detection occurs to establish the original bindings (Input Bindings) or it can be triggered by a browser event (i.e. Output Bindings). Once triggered, #1 applies.
  3. Change detection occurs top-down, starting from the root component towards the leaves. Think of this as a unidirectional tree of connected components, that starts with an AppComponent for the root.
  4. When a component's change detection strategy is changed to OnPush then during change detection, it will skip a component's entire sub-tree if the inputs have not changed.
like image 40
pixelbits Avatar answered Sep 25 '22 13:09

pixelbits