与ChangeDetectionStrategy.OnPush
一起使用Observables时,我想尽全力以赴。
该示例演示了想要显示某种加载消息(或者可能是简单的微调器动画)的常见情况:
Plnkr here
@Component({
selector: 'my-app',
template: `Are we loading?: {{loadingMessage}}`,
// Obviously "Default" will notice the change in `loadingMessage`...
// changeDetection: ChangeDetectionStrategy.Default
// But what is best practice when using OnPush?
changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements OnInit {
private loadingMessage = "Wait for it...";
constructor() {
}
ngOnInit() {
// Pretend we're loading data from a service.
// This component is only interested in the call's success
Observable.of(true)
.delay(2000)
.subscribe(success => {
if(success){
console.log('Pretend loading: success!');
// OnPush won't detect this change
this.loadingMessage = 'Success!';
}
});
}
}
我或多或少了解了
OnPush
的不可变性的要求,至少在我看来,谈论实际模型数据(可能保存在某种类型的商店中)目前是有意义的。因此,我有两个问题:
'Success!'
不会触发更改检测器?就不变性而言,值(value)已经改变,对吗? loadingMessage
时应如何实现轻量级内部组件状态(即ChangeDetectionStrategy.OnPush
)?如果有多种最佳做法,请指出正确的方向。 最佳答案
好问题。我从Savkin收到两个关于onPush
的引号(因为Angular.io文档似乎还没有关于此主题的任何信息):
第二个报价似乎更完整。 (太糟糕了,它被埋在了评论中!)
OnPush
不变性是指输入属性,而不是普通实例属性。如果loadingMessage
是输入属性,并且值已更改,则将在组件上执行更改检测。 (请参阅@Vlado对Plunker的回答。)
到目前为止,这是我所知道的:
OnPush
组件上执行(即, View 将更新)。在您的特定情况下,我对该 View 没有更新感到惊讶。关于为何不这样做,有两个猜测:delay()
使Angular看起来更像是setTimeout()
,而不是可观察的更改。 setTimeout
不会导致对OnPush
组件执行更改检测。在您的示例中,更改检测器在loadingMessage
的值更改前2秒钟完成了工作。 Observable
。也就是说,也许不仅仅是“可观察到的火灾” ...可能还必须是绑定(bind)的可观察到的火灾。在这种情况下,创建loadingMessage
(或什至是更通用的state
属性)作为Observable
本身将使您可以将模板绑定(bind)到其值(或多个异步值),请参阅this example plnkr。 更新2016-04-28:,绑定(bind)似乎必须包含| async
,如plnkr和this plnkr所示。 ChangeDetectorRef
注入(inject)到我们的组件中,并调用markForCheck()
方法以使更改检测在OnPush
组件和所有祖先组件上执行,直到根组件为止。如果仅更改 View 状态(即组件及其后代的本地状态),则可以使用detectChanges()
代替,它不会标记所有祖先组件以进行更改检测。 Plunker