我正在尝试结合使用 Observables 时的最佳实践ChangeDetectionStrategy.OnPush
.
该示例演示了想要显示某种加载消息(或者可能是简单的旋转动画)的常见场景:
点这里 http://plnkr.co/edit/QhqKigbUi343raXeX21D?p=preview
@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!'
触发变化检测器?就不变性而言,价值已经改变了,对吗?
- 轻量级内部组件应该如何状态(即
loadingMessage
)使用时实施ChangeDetectionStrategy.OnPush
?如果有多种最佳实践,请为我指出正确的方向。
好问题。我有两段萨夫金的话onPush
(因为 Angular.io 文档似乎还没有关于此主题的任何信息):
框架将检查OnPush
仅当组件的输入发生变化或组件的模板发出事件时。 --ref http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation
使用时OnPush
,Angular 只会在组件的任何输入属性发生更改、触发事件或可观察对象触发事件时检查组件。 --ref http://victorsavkin.com/post/110170125256/change-detection-in-angular-2(在@vivainio的评论回复中)
第二个引用似乎更完整。 (太糟糕了,它被埋在评论里了!)
为什么不分配新的字符串值Success!
触发
改变探测器?就不变性而言,价值已经改变了,对吗?
OnPush
不变性是指输入属性,而不是普通实例属性。如果loadingMessage
如果输入属性和值发生更改,则会在组件上执行更改检测。 (参见 @Vlado 对 Plunker 的回答。)
轻量级内部组件应该如何状态(即loadingMessage
)使用时实施ChangeDetectionStrategy.OnPush
?如果有多种最佳实践,请为我指出正确的方向。
到目前为止我所知道的是:
- If we change the internal state as part of handling an event, or part of an observable firing, change detection executes on the
OnPush
component (i.e., the view will update). In your particular case, I was surprised that the view did not update. Here are two guesses as to why not:
- Adding
delay()
让 Angular 看起来更像是setTimeout()
而不是可观察到的变化。setTimeout
s 不会导致更改检测执行OnPush
成分。在您的示例中,更改检测器已在值之前 2 秒完成其工作loadingMessage
被改变了。
- 就像 @Sasxa 在他的回答中显示的那样,您必须在模板中绑定到
Observable
。也就是说,也许它不仅仅是“可观察到的火灾”......也许它必须是bound可观察到的火。在这种情况下,创建loadingMessage
(或者甚至是更通用的state
财产)作为Observable
本身将允许您将模板绑定到它的值(或多个异步值),请参阅这个例子 plnkr http://plnkr.co/edit/OiBSDA8Kcsgl4vBF15xW?p=preview.
2016年4月28日更新:看来绑定必须包括| async
,如 plnkr 中所示,并且在这个 plnkr http://plnkr.co/edit/ezpbwhzowWkGQQKgn3FT?p=preview.
- 如果我们改变内部状态并且它不是事件处理或可观察触发的一部分,我们可以注入
ChangeDetectorRef
进入我们的组件并调用方法markForCheck()
导致更改检测在OnPush
组件以及直到根组件的所有祖先组件。如果仅更改视图状态(即组件及其后代的本地状态),detectChanges()
可以改为使用,这不会标记所有祖先组件以进行更改检测。Plunker http://plnkr.co/edit/qSENj5Oy3WSfx0O79ouF?p=preview
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)