簡體   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