奇数变化检测行为Angular 2+

时间:2019-01-27 07:44:38

标签: angular ngrx-store

您好,我正在处理一个大型应用程序,并且在更改检测方面遇到一些问题。我将尽力解释我的设置。

父组件ts:

使用changeDetection: ChangeDetectionStrategy.OnPush

我有一个可观察的变量

loaderOverlay$: Observable<boolean>;

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector)
);

此变量通过子组件的rxjs操作进行更新。然后执行rxjs流程。 (操作->减速器->选择器)

父组件HTML

<div *ngif="(loaderOverlay$ | async)"></div>

儿童#1组件(我在其中调度我的行动):

myFunction() {
  this.store.dispatch(new actions.LoaderOverlay(true));
}

我的问题是,一旦我分派动作,*ngif就会很不稳定。它似乎不按我想要的方式工作(调度操作,将值更改为true,以便div出现)。这很奇怪,因为如果我在减速器中console.log(action.payload)实际上是在更新值,但是*ngif无法正常工作。而且,甚至更奇怪的是,当我将鼠标悬停在其他组件上时,它似乎开始起作用。

我已经花了很多时间,并且我想将其范围缩小到更改检测范围,因为如果这样做的话,在父组件中:

ngAfterViewChecked(){
   this.changeDetector.detectChanges();
}

这似乎对我有用。我的问题是ngAfterViewChecked似乎被触发了很多次,我担心性能问题。

有人曾经遇到过这个问题吗?还是有人对正在发生的事情以及如何解决这个奇怪的问题有任何建议?

谢谢!

3 个答案:

答案 0 :(得分:4)

您的loaderOverlay$发出的值评估为true吗?我在stackblitz上创建了类似的代码(如您所述),但似乎无法重现您遇到的错误。这可能是在angular / ngrx中修复的错误,或者您发出的值未评估为true(选择不好,并返回未定义的内容)。尝试点击可观察对象并记录结果。

https://stackblitz.com/edit/angular-ngrx-update?file=src/app/app.component.css

稍后编辑:

正如Cristian Traina在评论中指出的那样,markForCheck(从异步管道内部)在从外部角度调用时不会触发更改检测。作为解决方法,您可以在管道中使用区域调度程序,或者检测更改的来源并修补该区域以触发角度内的更改检测(因为应用程序的其他区域可能存在问题)。

https://www.npmjs.com/package/ngx-zone-scheduler?activeTab=readme

public constructor(
  @Inject(ZoneScheduler)
  private readonly zoneScheduler: SchedulerLike,
) {}

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector),
  observeOn(this.zoneScheduler),
);

或者您也可以tick appRef

public constructor(
  private appRef: ApplicationRef,
) {}

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector),
  tap(_ => this.appRef.tick()),
);

答案 1 :(得分:3)

从您的示例来看,似乎onPush策略未正确使用。 onPush策略意味着,即使组件中的变量@inputs不变,组件也不一定会更新。根据我在示例中收集到的信息,父组件的@input引用没有更改,这意味着更改检测未如您期望的那样发生。

要解决此问题,我建议将父组件(订阅商店更新)更新为使用defaultStrategy或根据需要手动调用markForCheck()来触发更新。

答案 2 :(得分:3)

我有一个类似的问题。通过编辑输入字段,结果将从后端获取并显示在列表中。除非我将鼠标悬停或单击其他位置,否则列表不会更新。

我通过从后端获取数据后添加了手动更改检测来修复它。

constructor(private cd: ChangeDetectorRef) {}

fetchData.subscribe(results => {
   AddResultsToStore(results);
   this.cd.detectChanges();
});