但是,当我使用 ChangeDetectionStrategy.OnPush 时,无论我尝试什么,我都无法获取要更新的 ComponentA 中的值,即使是从我尝试过的根组件中:
一个组件有一个关联的视图。视图引用 DOM 并且是我们想要更新的内容。当您使用OnPush 时,如果组件的状态在外部发生变化,则需要将组件的视图标记为脏。
当您说even from the root component 时,这意味着您试图将错误的视图标记为脏视图。如果您想查看 ComponentA 的更改,则需要将该组件视图标记为脏。
类似的东西。
@Component({...})
public class ComponentA implements OnInit {
public count; // rendered in the view
public constructor(private _change: ChangeDetectorRef,
private _service: MyService) {
}
public onInit() {
this._service.getCounter().subscribe(value=> {
this.count = value; // will not update the view.
this._change.markForCheck(); // tell Angular it's dirty
});
}
}
所以上面的方法在 99% 的情况下都有效,但是如果 getCounter() 方法返回一个在 Angular 范围之外执行的可观察对象,并且您必须显式执行此操作,因为异步操作是自动分区的,那么您有使用zone.run() 方法。否则,即使您将视图标记为脏。 Angular 不会检查是否需要更新任何视图。除非您使用非 Angular 事件或在 Angular 之外显式运行,否则不应发生这种情况。
替代方法是使用async 管道,这是更简单的方法。
@Component({
template: `<span>{{count$ | async}}</span>`
})
public class ComponentA implement OnInit {
public count$: Observable<number>;
public constructor(private _service: MyService) {
}
public onInit() {
this.count$ = this._service.getCounter();
}
}
async 管道使用对ChangeDetectorRef 的引用也会将视图标记为脏视图。因此,它可以为您节省大量样板代码。
真实世界的情况是,有很多组件,如Componenta所有渲染翻译值,以及当所选语言更改时,我需要相应地更新所有这些翻译的值。我不想在每个单独的组件中构建一个侦听器并从那里调用 detectChanges
那么你最好的办法是使用async 管道并让你的组件反应。
如果我们谈论的是大规模和影响很多组件的事情,那么也许这个 root 组件应该将值作为@Input() 传递给组件,这也会触发它们呈现。虽然这会在所有组件之间建立耦合,但它表明您不必担心更新视图。