angular2中的“changeDetection: ChangeDetectionStrategy.OnPush”是
Does `changeDetection: ChangeDetectionStrategy.OnPush` in angular2 only works in one direction: top->bottom?
考虑这个 plunker
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
我们注意到,Child1
有changeDetection: ChangeDetectionStrategy.OnPush
上面的代码非常简单,parent
将一个对象发送到child1
,将完全相同的对象发送到child11
。
然后child11
更新对象的基元。
我们看到parent
和child1
的对象都是更新的,即使child1
有changeDetection: ChangeDetectionStrategy.OnPush
我猜changeDetection: ChangeDetectionStrategy.OnPush
只一种方式:从上到下。
这是真的吗?
如果是这样,这有什么原因吗?
根据 Savkin 的博客文章(好吧,它被埋在给 @vivainio 的评论中),
对于OnPush
,Angular 只会在以下情况下检查组件的更改(即检查模板绑定)
- 其任何输入属性都会更改
- 它触发事件(例如,按钮单击)
- 可观察量触发事件 [请注意,这并不完全正确。 可观察量需要在视图/模板中使用
| async
才能运行更改检测。 有关更多信息,请参阅有关此答案的评论。
如果满足这些条件中的任何一个,Angular 还会将树上的所有组件"标记"为需要更改检测的根组件。 然后,它将运行更改检测。 所有祖先组件,即使它们是为OnPush
策略配置的,也将检查是否有更改,因为它们当前是"标记"的。
这就解释了为什么父组件/应用和子组件 1 组件的视图会因组件 Child11 中的事件触发而更新。
这种"标记树"功能是设计使然,并且出于您在示例代码中显示的确切原因/方案 - 即,组件更改了一些应用程序数据,并且祖先组件在其视图中具有相同数据的数据绑定。 Angular 如何确保视图得到更新? 它必须将所有祖先"标记"到根组件,以便在运行更改检测时检查所有这些组件。
请注意,这并不涵盖所有方案。 假设更改的应用程序数据也存在于组件树的某个其他不相关的"分支"的组件视图中,并且该分支使用 OnPush
。 该组件视图将不会更新。
已经有一段时间了,但我遇到了类似的问题。因此,我想强调一个事实,即OnPush
并不总是改变父组件和子组件通信的工作方式。如果子组件的 @Input
属性是对象(引用类型),则在子组件上触发OnChanges
的唯一方法是当引用更改(创建新对象)时,而不考虑OnPush
。 OnPush
对于模板绑定更有意义,请求 angular 执行value equality
或只是比较引用。如果我错了,请纠正我。