3

考虑一下这个笨蛋

import {Component, OnInit, Input, OnChanges, DoCheck, ChangeDetectionStrategy, EventEmitter} from 'angular2/core'

@Component({
  selector: 'child11',
  template: `
      <button (click)="change_obj()">Button in Child11</button>
      <div>This is child11: {{my_obj11['name']}}</div>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class Child11 {
  @Input()
  my_obj11: Object;

  change_obj(){
    this.my_obj11['name'] = 'some other name';
  }  
}

@Component({
  selector: 'child1',
  template: `
      <child11 [my_obj11]="my_obj1"></child11>
      <div>This is child1: {{my_obj1['name']}}</div>
    `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  directives: [Child11]
})
export class Child1 {
  @Input()
  my_obj1: Object;
}

@Component({
  selector: 'parent',
  template: `
    <div>
      <child1 [my_obj1]="my_obj" ></child1>
      This is my_obj in parent: {{my_obj['name']}}
    </div>
    `,
  directives: [Child1]
})
export class App {
  my_obj: Object = {'name': 'name1'};
}

这里是组件之间的关系

 Parent
   |
 Child1
   |
 Child11

我们注意到Child1changeDetection: ChangeDetectionStrategy.OnPush

上面的代码很简单,parent发送一个对象child1,发送完全相同的对象到child11.

child11然后更新对象的原语。

我们看到parentandchild1的对象都被更新了,即使child1changeDetection: ChangeDetectionStrategy.OnPush

我猜changeDetection: ChangeDetectionStrategy.OnPush只有一种方式:从上到下。

真的吗?

如果是这样,这是有原因的吗?

4

2 回答 2

4

根据Savkin 的博客文章(好吧,它被埋在对@vivainio 的评论中),
使用OnPush,Angular 只会检查组件的更改(即检查模板绑定)

  • 它的任何输入属性发生变化
  • 它触发一个事件(例如,单击按钮)
  • 一个 observable 触发一个事件 [请注意,这并不完全正确。observable 需要| async在视图/模板中使用才能运行更改检测。有关更多信息,请参阅对此答案的评论。]

如果满足这些条件中的任何一个,Angular 也会将树上的所有组件“标记”为需要更改检测的根组件。然后它将运行更改检测。所有祖先组件,即使它们是为OnPush策略配置的,也会检查更改,因为它们当前是“标记的”。

这解释了为什么 Parent/App 和 Child1 组件的视图会由于组件 Child11 中的事件触发而更新。


这种“标记树”功能是设计使然,并且出于您在示例代码中显示的确切原因/场景 - 即,组件更改了一些应用程序数据,并且祖先组件在其视图中具有相同数据的数据绑定。Angular 如何确保视图会得到更新?它必须“标记”直到根组件的所有祖先,以便在运行更改检测时检查所有这些组件。

请注意,这并不涵盖所有场景。假设更改后的应用程序数据也出现在组件树的某个其他不相关的“分支”中的组件视图中,并且该分支使用OnPush. 该组件视图不会得到更新。

于 2016-04-25T16:02:33.297 回答
1

我知道已经有一段时间了,但我遇到了类似的问题。因此,我想强调一个事实,即OnPush并不总是改变父子组件通信的工作方式。如果子组件的@Input属性是对象(引用类型),那么在子组件上OnChanges触发的唯一方法是当引用更改(创建新对象)时,不管OnPush. 对于模板绑定、请求 Angular或只是比较引用OnPush更有意义。value equality如果我错了,请纠正我。

于 2016-07-20T09:58:07.440 回答