ChangeDetectionStrategy.OnPush 何时实际运行更改检测?

Jon*_*ter 5 javascript typescript angular

我建立一个角4应用程序包含多个组件,其中ChangeDetectionStrategyOnPush。虽然关于这个问题的 Angular 文档没有太多信息,但各种消息来源表示OnPush组件仅在它们的@Inputs 更改(新对象或基元)时更新。

但是,OnPush组件内部的各种事件似乎也会触发更改检测。但是,我注意到其他人不会触发更改检测。

ChangeDetectionStrategy.OnPush关于组件内部事件的具体规则是什么?

Ric*_*sen 5

来自变更检测策略: OnPush

这将通知 Angular 我们的组件只依赖于它的输入,并且任何传递给它的对象都应该被认为是不可变的。

它继续表明属性更改不会触发更改检测(被认为是不可变的),但对对象本身的更改会触发更改检测。

所以看起来关键标准是immutability。模板上引用的对象的更改触发器是,

  • 代码中的对象引用更改(父项更改输入值子项内的更改)触发更改检测。
  • 来自组件外部的对象属性更改不会触发更改检测。
  • 组件内部的对象属性更改触发更改检测。

我还没有测试过 observable 的变化,但它在其他地方作为触发器给出。(一个 observable 发射改变了一个对象引用,而不是它的属性)。

使用Angular版本5.2.0-beta.1 进行测试


扩展 RangleIO 示例

文章顶部引用的 RangleIO 页面有一个 Plunker,它说明通过Input()参数传递给组件的对象被认为是不可变的。子组件的变化检测器不会响应 Input 对象属性的变化。

但是,在复制Movie 组件内部的更改按钮后,可以看到在组件自己的代码中调用的对象属性更改将更改其视图。

这是代码,Plunker

电影.component.ts

@Component({
  selector: 'app-movie',
  styles: ['div {border: 1px solid black}'],
  template: `
    <div>
      <h3>{{ title }}</h3>
      <p>
        <label>Actor:</label>
        <span>{{actor.firstName}} {{actor.lastName}}</span>
      </p>
      <button type="button" (click)="changeActorProperties()">
        Inside Movie Component - Change Actor Properties (will change view)
      </button>
      <button type="button" (click)="changeActorObject()">
        Inside Movie Component - Change Actor Object (will change view)
      </button>
    </div>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MovieComponent {
  @Input() title: string;
  @Input() actor: Actor;

  changeActorProperties(): void {
    this.actor.firstName = 'Nicholas';
    this.actor.lastName = 'Cage';
  }

  changeActorObject(): void {
    this.actor = new Actor('Bruce', 'Willis');
  }
}
Run Code Online (Sandbox Code Playgroud)

app.component.ts

@Component({
  selector: 'app-root',
  template: `
    <h1>MovieApp</h1>
    <p>{{ slogan }}</p>
    <button type="button" (click)="changeActorProperties()">
      Outside Movie Component - Change Actor Properties (will not change Movie view)
    </button>
    <button type="button" (click)="changeActorObject()">
      Outside Movie Component - Change Actor Object (will change Movie view)
    </button>
    <app-movie [title]="title" [actor]="actor"></app-movie>`
})
export class AppComponent {
  slogan = 'Just movie information';
  title = 'Terminator 1';
  actor = new Actor('Arnold', 'Schwarzenegger');

  changeActorProperties(): void {
    this.actor.firstName = 'Nicholas';
    this.actor.lastName = 'Cage';
  }

  changeActorObject(): void {
    this.actor = new Actor('Bruce', 'Willis');
  }
}
Run Code Online (Sandbox Code Playgroud)


Con*_*Fan 5

本博客文章中的角大学包含有关事件,当使用触发变化检测一些迹象ChangeDetectionStrategy.OnPush

除了组件 Input() 引用的更改之外,在其他几种情况下会触发 OnPush 更改检测器,它也会被触发,例如:

  • 如果组件事件处理程序被触发
  • 如果通过异步管道链接到模板的 observable 发出一个新值

他们添加了以下建议:

因此,如果我们记得在模板级别使用异步管道尽可能多地订阅任何 observable,我们将获得以下几个优势:

  • 我们将使用 OnPush 遇到更少的变更检测问题
  • 如果我们需要,我们将在以后更容易地从默认更改检测策略切换到 OnPush
  • 不可变数据和@Input() 引用比较不是使用 OnPush 实现高性能 UI 的唯一方法:反应式方法也是有效使用 OnPush 的一种选择

在Disqus 上的“Angular 2 上的变更检测”问题之后的评论中,Viktor Savkin 解释说:

使用 OnPush 检测器时,框架将在 OnPush 组件的任何输入属性发生更改、触发事件或 observable 触发事件时检查该组件。