【问题标题】:Unexpected behaviour of change detection with OnPush strategy使用 OnPush 策略进行变更检测的意外行为
【发布时间】:2020-02-11 23:08:45
【问题描述】:

我遇到了变化检测器(使用 OnPush)的非常奇怪的行为。我什至无法向自己解释它,也不知道如何解决它。尽管如此,我还是在stackblitz 上的非常简单的示例中重现了这种行为

https://stackblitz.com/edit/angular-h28cw8

共有三个组件:主要的app 组件、data 组件和loading indicator 组件。当用户单击Go to data 链接时,主组件可以通过<router-outlet> 显示data 组件。还有服务(也就是应用程序的状态)。当用户单击Go to data 时,data 组件会向该服务请求数据,该数据的加载有一定的延迟。为了模拟这种延迟,我使用了 rxjs 计时器,但使用 HttpClient 时,行为是完全一样的。数据和加载值通过使用async 管道绑定。但是由于某种原因,数据按预期显示,但loading 不是(最好说它有时会工作,但并非总是如此)。这会导致加载指示不会出现在屏幕上。我还将值记录到控制台,很容易看到loading$ observable 发出值,但@Input 绑定由于某种原因不起作用。为什么会这样,以及如何解决?

【问题讨论】:

  • 如果我将加载组件移动到数据组件中,它对我有用:stackblitz.com/edit/angular-s7ywxj。我使用 OnPush,但我不使用异步管道,所以我习惯于相当频繁地调用 this.changeDetector.detectChanges()。也许我会开始迁移到异步管道方法(前提是它可以与 OnPush 一致地工作)

标签: angular angular-changedetection


【解决方案1】:

它不工作的原因是因为您在检查父组件后从子组件发出 this._loading.next(true) 值。

异步管道确实会触发订阅并且按预期工作,即运行cdRef.markForCheck();。但它不运行更改检测,而只是将使用 AsyncPipe 的组件标记为要检查。一旦新的更改检测周期开始,您的组件就会识别输入更改。

要修复它,您可以将 this._common.getData() 包装在子组件的 microtask 中

Promise.resolve().then(() => {
   this._common.getData();
});

Forked Stackblitz

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-06
  • 2019-08-31
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 2017-09-28
  • 2017-06-15
相关资源
最近更新 更多