[英]Unexpected behaviour of change detection with OnPush strategy
I've faced with very strange behaviour of change detector (with OnPush).我遇到了非常奇怪的变化检测器行为(使用 OnPush)。 I am not even able to explain it to myself and don't know how to fix it.
我什至无法向自己解释它,也不知道如何解决它。 Nevertheless I've reproduced this behaviour in very simple example on
stackblitz
尽管如此,我还是在
stackblitz
上的stackblitz
非常简单的例子中重现了这种行为
https://stackblitz.com/edit/angular-h28cw8 https://stackblitz.com/edit/angular-h28cw8
There are three components: main app
component, data
component and loading indicator
component.共有三个组件:主
app
组件、 data
组件和loading indicator
组件。 Main component can display the data
component through the <router-outlet>
when user click the Go to data
link.当用户单击
Go to data
链接时,主组件可以通过<router-outlet>
显示data
组件。 There is also service (aka state of the application).还有服务(也就是应用程序的状态)。 When user click
Go to data
, the data
component requests this service for data, which is loaded with some delay.当用户点击
Go to data
, data
组件请求该服务获取数据,加载有一些延迟。 To emulate this delay I use rxjs timer, but with HttpClient
the behaviour is absolutely the same.为了模拟这种延迟,我使用了 rxjs 计时器,但使用
HttpClient
的行为完全相同。 Data & loading values are binded by the use of async
pipe.数据和加载值通过使用
async
管道绑定。 But for some reason data is displayed as expected, but loading
isn't (it's better to say that it works from time to time, but not always).但是由于某种原因数据按预期显示,但
loading
不是(最好说它不时起作用,但并非总是如此)。 That causes the loading indicatior doesn't appear on the screen.这会导致加载指示符不会出现在屏幕上。 I also log values to the console where it's easy to see that the
loading$
observable emits value, but the @Input
binding doesn't work for some reason.我还将值记录到控制台,在那里很容易看到
loading$
observable 发出值,但@Input
绑定由于某种原因不起作用。 Why it works so, and how to fix that?为什么它如此有效,以及如何解决这个问题?
The reason why it is not working is because you're emitting this._loading.next(true)
value from child component after parent component has been checked.它不起作用的原因是因为您在检查父组件后从子组件发出
this._loading.next(true)
值。
Async pipe does triggers subscription and works as intended , that is runs cdRef.markForCheck();
异步管道确实会触发订阅并按预期工作,即运行
cdRef.markForCheck();
. . But it doesn't run change detection but rather only marks component, where AsyncPipe is used, to be checked .
但它不运行更改检测,而只是将使用 AsyncPipe 的组件标记为要检查。 Once a new change detection cycle starts your component will recognize input changes.
一旦新的更改检测周期开始,您的组件将识别输入更改。
To fix it you can wrap this._common.getData()
in microtask in your child component要修复它,您可以将
this._common.getData()
包装在您的子组件中的微任务中
Promise.resolve().then(() => {
this._common.getData();
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.