繁体   English   中英

Angular 嵌套 ngFor 不会触发更改检测

[英]Angular Change Detection is not triggered with nested ngFor

我目前正在开发一个带有 NgRx 存储的更大的 Angular 项目。 该应用程序包含一个无限滚动列表,当到达末尾时会显示一些骨架项目,当请求完成时,这些骨架项目会被真实项目下推。

在一个组件中,我们需要一个分组/嵌套列表,这会导致嵌套*ngFor 由于建议使用 NgRx,因此该组件使用ChangeDetectionStrategy.OnPush

现在,当从后端加载列表值时,即使请求已经完成很长时间,列表也需要很长时间才能更新(有时只有在浏览器内单击时才会更新)。 我的第一个猜测是变更检测存在问题。

这是我的组件目前的样子的摘录:

<ul cdkScrollable #groupList>
  <li *ngFor="let dayGroup of groupsWithSkeleton$ | ngrxPush | keyvalue: asIsOrder;
              let i = index;
              trackBy: trackByKey">
    <div>{{ dayGroup.key | date }}</div>
    <ul>
      <li *ngFor="let subGroup of dayGroup.value | keyvalue: asIsOrder;
                  let i = index;
                  trackBy: trackByKey">
        <!-- stuff -->
      </li>
    </ul>
  </li>
</ul>
private groups$: Observable<Groups> = this.store.select(
  Selectors.selectGroups
);

constructor(readonly store: Store<AppState>) {
  this.groupsWithSkeleton$ = combineLatest([
    this.groups$,
    this.isLoadingOrHasMoreItemsAvailable$
  ]).pipe(
    map(([groups, isLoadingOrHasMoreItemsAvailable]) => {
      const skeleton: Groups = isLoadingOrHasMoreItemsAvailable ? this.skeletonMap : new Map();
      return new Map([...groups, ...skeleton]);
    })
  );
  // [...] more assignments
}

我已经找到了一个可行的解决方案,但我认为它相当难看,我真的不明白为什么这首先不起作用。 (它仍然不是非常快但可以接受。)

解决方案是在创建带有骨架项目的组后添加它:

tap(() => {
  changeDetectorRef.markForCheck();
  changeDetectorRef.detectChanges();
})

我还用 MWE 创建了一个 StackBlitz: https://stackblitz.com/edit/angular-ivy-7ycaxv?file=src/app/app.component.ts

也许有人可以帮助我找到潜在的问题和更好的解决方案。

这是一个棘手的问题,文档实际上并没有明确说明:

我们可以在滚动调度器的代码源中找到关于scrolled的:

为了避免对每个滚动事件进行更改检测,从此 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 发出的所有事件都将在 Angular 区域之外运行。 如果由于滚动事件而需要更新任何数据绑定,则必须 * 使用 `NgZone.run 运行回调

这就是为什么您需要显式调用会触发 CD 的东西的原因。 在您的情况下, changeDetectorRef.detectChanges()就足够了!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM