Reputation: 2343
Consider the following code
import {Component, OnInit, Input, OnChanges, DoCheck, ChangeDetectionStrategy} from 'angular2/core'
@Component({
selector: 'child1',
template: `
<div>reference change for entire object: {{my_obj1.name}}</div>
<div>reassign primitive in property of object: {{my_obj2.name}}</div>
<div>update primitive in property of object: {{my_obj2.num}}</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class Child1 {
@Input()
my_obj1: Object = {'name': ''};
@Input()
my_obj2: Object = {'name': '', 'num': 0};
ngDoCheck() {
console.log('check from child1');
console.log(this.my_obj1);
console.log(this.my_obj2);
}
}
@Component({
selector: 'parent',
template: `
<div>
<child1
[my_obj1]="my_obj1"
[my_obj2]="my_obj2"
>
</child1>
<button (click)="change_obj1()">
Change obj1
</button>
</div>
`,
directives: [Child1]
})
export class App {
my_obj1: Object = {'name': 'name1'};
my_obj2: Object = {'name': 'name2', 'num': 0};
change_obj1() {
this.my_obj1 = {'name': 'change1'}
this.my_obj2['name'] = 'change2';
this.my_obj2['num'] += 1;
}
}
From the experiment I made, here is my understanding of the current Angular2
change detection strategy, can someone verify it if its true?
Angular2 by default checks for value equality when doing change detection. If there are no ChangeDetectionStrategy.OnPush
, every watched variable in component tree is checked for value equality. If value equality is false, that specific component will be rerender, and if value equality if true, that specific component will not be rerender.
If you add ChangeDetectionStrategy.OnPush
to a component. The behavior changes as follows
i. If variable inside the component have reference change, the component is rerendered, and child component is checked for change detection (its specific change detection algorithm value/reference check depends on ChangeDetectionStrategy.OnPush
)
ii. If variable inside the component don't have reference change, the component is not rerendered, and child component is not checked for change detection, regardless of presence of ChangeDetectionStrategy.OnPush
Is this the correct interpretation?
Upvotes: 2
Views: 2637
Reputation: 364677
I reworked your plunker a bit: new plunker
Since primitive values are immutable, there is no difference between reassigning and updating – the primitive gets the new immutable value, so I removed the "updating" code. Also, it is very helpful to split out assigning a new object reference (which does trigger change detection) and assigning a new primitive value (which does not trigger change detection). So I did that also.
If you run my Plunker we can make the following observations:
OnPush
component
will update the component's view. The template bindings are checked for changes. In addition, child components are checked (assuming they are not using OnPush
).OnPush
component will not update the component's view. The template bindings are not checked for changes. In addition, child components are not checked, regardless of whether they are using OnPush
or not.ngDoCheck()
is always called on the first OnPush
component, regardless of whether the template bindings are checked for change or not. I find this odd (who knows, maybe it is a bug). So, just because ngDoCheck()
is called does not necessarily imply that template bindings are checked.Note, when a template binding change is detected, only that change is propagated to a child component or the DOM (as appropriate, depending on the binding type). If the binding change resulted in a DOM change, the entire component is not rerendered. Only that bound DOM data is updated, and the browser will only then update that one DOM element. (This is unlike some other frameworks, where they do rerender the entire template if any change is found. This helps make Angular faster.)
Upvotes: 4
Reputation: 8670
This post explains it in detail pretty well:
http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation
In short you're assumptions are correct. Angular2 must be conservative and check for value equality, i.e. it must do a 'deep check' of the objects referenced.
With ChangeDetectionStrategy.OnPush
, components will only be updated if the references to their input objects have changed.
Thus is why immutable objects can be preferred data structures--if we must update an object, the component is now referencing a new object. And it is therefore easy for angular to know which components must be updated.
Performant behavior can also be achieved with observables, through the ChangeDetectorRef.markForCheck();
method.
This is explained here:
http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
Upvotes: 0