2

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?

  1. 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.

  2. 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?

4

2 回答 2

4

我对你的 plunker 做了一些修改:new plunker

由于原始值是不可变的,重新分配和更新之间没有区别——原始获取新的不可变值,所以我删除了“更新”代码。此外,将分配一个新的对象引用(会触发更改检测)和分配一个新的原始值(不会触发更改检测)分开是非常有帮助的。所以我也这样做了。

如果您运行我的Plunker,我们可以进行以下观察:

  1. 更改作为组件 引用类型的输入属性将更新组件的视图。检查模板绑定是否有更改。此外,检查子组件(假设它们不使用)。OnPushOnPush
  2. OnPush更改组件的引用类型中包含的原始属性不会更新组件的视图。不检查模板绑定的更改。此外,不检查子组件,无论它们是否正在使用OnPush
  3. ngDoCheck()总是在第一个OnPush组件上调用,无论是否检查模板绑定是否更改。我觉得这很奇怪(谁知道呢,也许这是一个错误)。因此,仅仅因为ngDoCheck()被调用并不一定意味着模板绑定被检查。

请注意,当检测到模板绑定更改时,只会将该更改传播到子组件或 DOM(视情况而定,取决于绑定类型)。如果绑定更改导致 DOM 更改,则不会重新呈现整个组件。只有绑定的 DOM 数据被更新,浏览器只会更新那个 DOM 元素。(这与其他一些框架不同,如果发现任何更改,它们会重新呈现整个模板。这有助于使 Angular 更快。)

于 2016-04-18T20:51:19.040 回答
0

这篇文章很好地解释了它:

http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation

简而言之,您的假设是正确的。Angular2 必须保守并检查值是否相等,即它必须对引用的对象进行“深度检查”。

使用ChangeDetectionStrategy.OnPush时,只有在对其输入对象的引用发生更改时才会更新组件。

这就是为什么不可变对象可以成为首选数据结构的原因——如果我们必须更新一个对象,组件现在正在引用一个新对象。因此,Angular 很容易知道哪些组件必须更新。

ChangeDetectorRef.markForCheck();通过该方法,也可以使用 observables 实现高性能行为。

这在这里解释:

http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

于 2016-04-18T19:35:02.180 回答