使用OnPush策略时从ngOnChanges更改组件输入

问题描述 投票:2回答:1

我在Angular 6应用程序中遇到问题:

问题

假设我有两个组成部分:父母和孩子。

孩子有2个输入。当1个输入发生更改时,子组件在ngOnChanges()内向父组件发出东西。

然后,父组件更改子组件的第二个输入。我希望子组件的更改检测会再次被调用-但不是。子组件的视图显示第二个输入的旧值。


防御

该应用程序具有以下定义:

  1. 所有组件都使用更改检测策略OnPush。包括根组件。
  2. 我正在使用ngrx商店。不能在reducer内调用markForCheck()或detectChanges()。
  3. [数据使用异步管道传递到子组件,因为它来自使用选择器的存储(可观察)。
  4. 我不能更早地更改第二个输入(例如,在父组件上)-它必须在子组件获得第一个输入的更改之后发生。

为了说明这种情况,我创建了一个简单的演示项目。那里我不使用存储,所以我没有任何选择器..相反,我使用rxjs Subject来使用异步管道。

这里是:

https://angular-ccejq4.stackblitz.io

查看控制台以了解发生的情况和时间。


错误的解决方案

我已经尝试过的:

  1. 将根组件的更改检测策略更改为默认值。它可以工作,但这不是一个好的解决方案,因为它会导致性能问题。
  2. 在emit(!)之前和之后调用markForCheck()-无效。
  3. 在emit(!)之前和之后调用detectchanges()-不起作用。
  4. 在父组件上订阅选择器,而不使用异步管道-不在工作。
  5. 在setTimeout内调用发射-IT工作。但是有更好的解决方案吗?更受角度驱动的。因为此解决方案更像是一种解决方法。
  6. 使用ngAfterViewInit / ngAfterViewChecked并发出,从那里调用markForCheck()和detectChanges()-不起作用。

我发现新值到达异步管道。然后异步管道调用markForCheck()。但它不会调用detectChanges()..因此,更改检测周期将不会运行。仅在下一个更改检测周期中,视图才会正确更改-正如您在我的演示应用程序上看到的那样。


有什么想法吗?

谢谢!

angular rxjs ngrx angular2-changedetection angular-changedetection
1个回答
0
投票

[我先说,是一个很好的细节问题,而且解释清楚。您确实遇到了角度变化检测的警告。

[在ngOnChanges内部,没有直接的方法来触发另一个更改检测。否则,您将有可能陷入困境。同样在性能方面,他们不允许这样做。您需要找到一种进入下一个JS执行周期的方法

setTimeout不是克服这个问题的不错选择。您可以将其放在发射周围:

setTimeout(() => this.secondEmitter.emit(this.first));

或者您可以将其置于markForCheck通话周围:

setTimeout(() => this.cdRef.markForCheck());

但是我同意你的看法,这有点让人讨厌,但有时您只需要解决它。如果您真的无法做到,那还有另一种方法。您的BehaviorSubject本质上是同步可观察的。但是,您可以在模板中进行async订阅,以使用asyncScheduler

private second = new BehaviorSubject(0);

readonly second$ = this.second.asObservable().pipe(
  observeOn(asyncScheduler)
)

constructor() {
  this.second.next(0);
  this.second$.subscribe((lastval) => {
    console.log(`second subscription update to ${lastval}`);
  });
}

从最后一个选项开始,我为您的stack作了分叉>

这将使对它的所有订阅在下一个事件循环周期之后都收到消息。

© www.soinside.com 2019 - 2024. All rights reserved.