在ChangeDetectionStrategy.OnPush
旁边使用Observable时,我试图围绕最佳做法。
该示例演示了想要显示某种加载消息(或者可能是简单的微调器动画)的常见场景:
@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
)?如果有多种最佳实践,请指出正确的方向。答案 0 :(得分:44)
好问题。我有两个来自Savkin的关于onPush
的引用(因为Angular.io文档似乎没有关于这个主题的任何信息):
只有在输入更改或组件模板发出事件时,框架才会检查
OnPush
组件。 - ref使用
OnPush
时,Angular只会在其任何输入属性发生更改时,触发事件时或者当observable触发事件时检查该组件。 - ref(在对@vivainio的评论回复中)
第二句话似乎更完整。 (太糟糕了,它被埋没在评论中!)
为什么新字符串值
Success!
的赋值不会触发 改变探测器?就不变性而言,价值已发生变化,对吗?
OnPush
不变性是指输入属性,而不是普通的实例属性。如果loadingMessage
是输入属性并且值已更改,则将在组件上执行更改检测。 (参见@Vlado对Plunker的回答。)
使用
loadingMessage
时,如何实现轻量级内部组件状态(即ChangeDetectionStrategy.OnPush
)?如果有多种最佳实践,请指出正确的方向。
这是我目前所知道的:
OnPush
组件上执行(即视图将更新)。在您的特定情况下,我很惊讶该视图没有更新。这里有两个猜测,为什么不:
delay()
使Angular更像是setTimeout()
而不是可观察到的更改。 setTimeout
不会导致OnPush
组件上的更改检测执行。在您的示例中,更改检测器已在loadingMessage
的值更改之前2秒完成其工作。Observable
。也许它不仅仅是“一个可观察到的火焰”......也许它必须是一个强烈的绑定可观察物。在这种情况下,创建loadingMessage
(或甚至更通用的state
属性)作为Observable
本身将允许您将模板绑定到其值(或多个异步值),请参阅{ {3}}。| async
,如plnkr和this example plnkr所示。< / LI>
ChangeDetectorRef
注入到我们的组件中并调用方法markForCheck()
以使更改检测在{ {1}}组件和所有祖先组件直到根组件。如果仅改变视图状态(即,组件本地的状态以及其后代的状态),则可以使用OnPush
代替,这不会标记用于变化检测的所有祖先组件。 this plnkr 答案 1 :(得分:6)
AFAIK,在directly with observables工作时使用OnPush
:
//our root app component
import {Component, OnInit, ChangeDetectionStrategy} from 'angular2/core'
import {Observable} from 'rxjs/Observable';
import 'rxjs/Rx';
@Component({
selector: 'my-app',
template: `Are we loading?: {{ loadingMessage |async }}`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements OnInit {
private loadingMessage;
constructor() { }
ngOnInit() {
this.loadingMessage = Observable.of(true)
.delay(2000)
}
}
答案 2 :(得分:1)
使用此ChangeDetectionStrategy.OnPush
,您告诉您的组件只监听其输入属性的更改。
我在您的示例中添加了加载组件,以向您展示它是如何工作的: http://plnkr.co/edit/k5tkmcLlzkwz4t5ifqFD?p=preview