简体   繁体   English

即使在设置了OnPush标志的情况下,为什么在更改检测期间Angular2都会同时捕获参考更改和原始更改?

[英]Why is both reference change and primitive change catch by Angular2 during change detection even with OnPush flag set?

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更改检测策略的理解,有人可以验证它是否正确吗?

  1. Angular2 by default checks for value equality when doing change detection. 默认情况下,Angular2在进行更改检测时会检查值是否相等。 If there are no ChangeDetectionStrategy.OnPush , every watched variable in component tree is checked for value equality. 如果没有ChangeDetectionStrategy.OnPush ,则检查组件树中每个监视的变量的值是否相等。 If value equality is false, that specific component will be rerender, and if value equality if true, that specific component will not be rerender. 如果值相等为false,则将重新呈现该特定组件,如果值相等为true,则将不重新呈现该特定组件。

  2. If you add ChangeDetectionStrategy.OnPush to a component. 如果将ChangeDetectionStrategy.OnPush添加到组件。 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 ) 如果组件内部的变量具有参考更改,则重新呈现该组件,并检查子组件以进行更改检测(其特定的更改检测算法值/参考检查取决于ChangeDetectionStrategy.OnPush

    ii. 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 如果组件内的变量没有引用更改,则无论ChangeDetectionStrategy.OnPush是否存在,都不会重新呈现该组件,并且不检查子组件进行更改检测。

Is this the correct interpretation? 这是正确的解释吗?

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: 如果您运行我的Plunker,我们可以进行以下观察:

  1. changing an input property that is a reference type on an OnPush component will update the component's view. 更改作为OnPush组件上的引用类型的输入属性将更新组件的视图。 The template bindings are checked for changes. 检查模板绑定是否有更改。 In addition, child components are checked (assuming they are not using OnPush ). 此外,还会检查子组件(假设它们未使用OnPush )。
  2. changing a primitive property that is contained within a reference type on an OnPush component will not update the component's view. 更改OnPush组件的引用类型中包含的原始属性将不会更新组件的视图。 The template bindings are not checked for changes. 不检查模板绑定的更改。 In addition, child components are not checked, regardless of whether they are using OnPush or not. 此外,无论子组件是否正在使用OnPush ,都不会对其进行检查。
  3. ngDoCheck() is always called on the first OnPush component, regardless of whether the template bindings are checked for change or not. 始终在第一个OnPush组件上调用ngDoCheck()无论是否检查模板绑定是否更改。 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. 因此,仅因为ngDoCheck()并不一定意味着已检查模板绑定。

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). 注意,当检测到模板绑定更改时,仅将该更改传播到子组件或DOM(视情况而定,具体取决于绑定类型)。 If the binding change resulted in a DOM change, the entire component is not rerendered. 如果绑定更改导致DOM更改,则不会重新呈现整个组件。 Only that bound DOM data is updated, and the browser will only then update that one DOM element. 仅更新该绑定的DOM数据,然后浏览器将仅更新该DOM元素。 (This is unlike some other frameworks, where they do rerender the entire template if any change is found. This helps make Angular faster.) (这与其他一些框架不同,在其他框架中,如果发现任何更改,它们确实会重新呈现整个模板。这有助于使Angular更快。)

This post explains it in detail pretty well: 这篇文章很好地详细解释了它:

http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation 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, ie it must do a 'deep check' of the objects referenced. Angular2必须是保守的并检查值是否相等,即它必须对引用的对象进行“深度检查”。

With ChangeDetectionStrategy.OnPush , components will only be updated if the references to their input objects have changed. 使用ChangeDetectionStrategy.OnPush ,只有在更改了其输入对象的引用的情况下,才会更新组件。

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. 因此,Angular很容易知道必须更新哪些组件。

Performant behavior can also be achieved with observables, through the ChangeDetectorRef.markForCheck(); 通过ChangeDetectorRef.markForCheck();也可以使用可观察对象来实现性能行为ChangeDetectorRef.markForCheck(); method. 方法。

This is explained here: 此处说明:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM