Angular OnPush:如何强制从外部检测更改?
Angular OnPush: how do I force changes to be detected from outside?
我有一个场景,我有两个组件并排放置,ComponentA 和 ComponentB。他们都使用一个服务Service。
ComponentB 包含一个按钮,它将在服务中生成 属性,Service.counter,上升 1。
ComponentA 呈现 Service.counter 的值。
但是,当我使用 ChangeDetectionStrategy.OnPush 时,无论我尝试什么,我都无法获取要更新的 ComponentA 中的值,即使是从我试过的根组件也是如此:
this.cdr.markForCheck();
this.cdr.detectChanges();
this.ar.tick();
this.zone.run(() => {});
无需更改 ComponentA,如何确保它始终显示正确的值?
(现实世界的场景是有很多组件,例如Componenta所有渲染翻译值,当所选的语言更改时,我需要所有这些翻译值来相应地更新。我不想构建听众进入每个单独的组件并从那里调用 detectChanges)
However, when I use ChangeDetectionStrategy.OnPush, no matter what I try, I cannot get the value in ComponentA to update, even from the root component, where I tried this:
一个组件有一个关联的视图。该视图引用 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()
方法 returns 一个在 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
的引用也会将视图标记为脏视图。所以它可以让您免于编写大量样板代码。
The real world scenario is that there's a lot of components like ComponentA all rendering translated values, and when the selected language changes, I need all these translated values to update accordingly. I don't want to build a listener into each individual component and call detectChanges from there
那么你最好的选择是使用 async
管道并使你的组件具有反应性。
如果我们谈论的是大规模的东西并且影响很多组件,那么也许这个 root 组件应该将值作为 @Input()
传递给组件这也将触发它们被渲染。虽然这会在所有组件之间创建耦合,但它表明您不必担心更新视图。
我有一个场景,我有两个组件并排放置,ComponentA 和 ComponentB。他们都使用一个服务Service。
ComponentB 包含一个按钮,它将在服务中生成 属性,Service.counter,上升 1。
ComponentA 呈现 Service.counter 的值。
但是,当我使用 ChangeDetectionStrategy.OnPush 时,无论我尝试什么,我都无法获取要更新的 ComponentA 中的值,即使是从我试过的根组件也是如此:
this.cdr.markForCheck();
this.cdr.detectChanges();
this.ar.tick();
this.zone.run(() => {});
无需更改 ComponentA,如何确保它始终显示正确的值?
(现实世界的场景是有很多组件,例如Componenta所有渲染翻译值,当所选的语言更改时,我需要所有这些翻译值来相应地更新。我不想构建听众进入每个单独的组件并从那里调用 detectChanges)
However, when I use ChangeDetectionStrategy.OnPush, no matter what I try, I cannot get the value in ComponentA to update, even from the root component, where I tried this:
一个组件有一个关联的视图。该视图引用 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()
方法 returns 一个在 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
的引用也会将视图标记为脏视图。所以它可以让您免于编写大量样板代码。
The real world scenario is that there's a lot of components like ComponentA all rendering translated values, and when the selected language changes, I need all these translated values to update accordingly. I don't want to build a listener into each individual component and call detectChanges from there
那么你最好的选择是使用 async
管道并使你的组件具有反应性。
如果我们谈论的是大规模的东西并且影响很多组件,那么也许这个 root 组件应该将值作为 @Input()
传递给组件这也将触发它们被渲染。虽然这会在所有组件之间创建耦合,但它表明您不必担心更新视图。