changeDetection:ChangeDetectionStrategy.OnPush似乎无法正常工作?

时间:2018-02-04 07:19:46

标签: angular angular2-changedetection

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

问题:有人可以帮我理解为什么我的原型changeDetection: ChangeDetectionStrategy.OnPush仍允许我更新内部值name吗?如果这不是ChangeDetectionStrategy.OnPush想要阻止的,它应该做什么?

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';
  }
}

3 个答案:

答案 0 :(得分:3)

因为原始数据类型是不可变的 - 如果你更改它,它的引用也会改变,所以组件的ChangeDetectorRef知道它必须检测更改(因为OnPush查找引用更改,而不是数组中的数据突变,对象)。如果要在基元上避免这种情况,可以使用detach() / reattach()在ChangeDetectorRef实例上手动停用/激活它:

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

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

 constructor(private ref: ChangeDetectorRef) {}

  public changeName() {
    this.ref.detach();
    this.name = 'Inner';
  }
}

答案 1 :(得分:2)

默认的更改检测策略是保守的,并检查 可能 更改的所有绑定。通常,只要 [input] 发生更改,或任何组件发生(事件),就会触发更改检测周期。

通过将组件的更改检测策略更改为 OnPush ,Angular仅在组件的输入 实际更改时检查更新。通过允许在变化检测期间跳过整个子树,这使得Angular可以更有效地进行变化检测。

以下是一篇很好的文章:https://vsavkin.com/immutability-vs-encapsulation-90549ab74487

有助于理解的一些要点是:

  1. 默认情况下,触发更改检测摘要时,将检查所有绑定是否包含所有组件的更新,无论更改最初来自何处。
  2. 发生更改检测以建立原始绑定(输入绑定),或者可以由浏览器事件(即输出绑定)触发。触发后,#1适用。
  3. 自上而下发生变化检测,从根部分开始向叶子发展。可以将其视为连接组件的单向树,从根的AppComponent开始。
  4. 当组件的更改检测策略更改为OnPush时,在更改检测期间,如果输入未更改,它将跳过组件的整个子树。

答案 2 :(得分:1)

  

仅当父视图绑定发生更改且子级更改时才更新状态   使用ChangeDetectionStrategy.OnPush初始化组件视图。

在示例中,您只需将以下行添加到子Hello组件中。

 ngOnChanges(simpleChange : SimpleChanges){
   console.log(simpleChange)
  }

您将看到,单击按钮时,视图会随着父Bindings的更改而更改,这是在父项和子项中更新视图的原因。