You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何有效实现Angular Deferrable Views?解决现有实现的两大问题

解决Angular Deferrable Views的两个核心问题

问题根源分析

  1. 错误时卡在@placeholder:原@defer的when条件仅判断beData是否有数据,后端返回错误时beData始终为空,导致when条件不满足,无法进入主块显示错误信息;且@defer的@error块仅处理组件加载失败(如子组件无法加载),而非数据请求错误。
  2. @loading块不触发:原@defer的when条件未关联加载状态,只有when条件满足时才会开始加载主块内容,加载状态isLoading未参与@defer的触发逻辑,导致即使超时也不会显示loading。

修改后的完整代码

my-component.ts

@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [...],
  templateUrl: './my.component.html',
  styleUrl: './my.component.scss',
})
export class MyComponent implements OnInit, OnDestroy {
  public types = ['chart', 'list'];
  public beData = signal<BeData[]>([]); // 改为signal提升响应性
  public isLoading = signal(false);
  public isError = signal(false);
  private _destroy$ = new Subject<boolean>();

  constructor(private myService: MyService) {}

  public ngOnInit(): void {
    this.fetchData();
  }

  private fetchData(): void {
    this.isLoading.set(true);
    this.isError.set(false);
    this.beData.set([]);

    this.myService
      .getBeData()
      .pipe(
        takeUntil(this._destroy$),
        catchError((err) => {
          console.error('Error fetching data', err);
          this.isError.set(true);
          return EMPTY; // 避免错误数据进入subscribe
        }),
        finalize(() => this.isLoading.set(false)),
      )
      .subscribe((data) => {
        this.beData.set(data);
      });
  }

  public ngOnDestroy(): void {
    this._destroy$.next(true);
    this._destroy$.complete();
  }
}

my-component.html

<div class="my-container">
  @for (type of types; track $index) {
    <div class="wrapper">
      @defer (when !isLoading() && (beData().length > 0 || isError())) {
        @if (isError()) {
          <div class="error-message">
            An error occurred while fetching data.
          </div>
        } @else if (type === "chart") {
          <app-child-one></app-child-one>
        } @else if (type === "list") {
          <app-child-two></app-child-two>
        } @else {
          <div class="empty-message">No data available.</div>
        }
      } @placeholder {
        @if (type === "chart") {
          <app-skeleton-one></app-skeleton-one>
        } @else if (type === "list") {
          <app-skeleton-two></app-skeleton-two>
        }
      } @loading (after 2s; minimum 1s) {
        <mat-spinner diameter="40"></mat-spinner>
      } @error {
        <div class="error-message">Failed to load the component.</div>
      }
    </div>
  }
</div>

关键修改说明

  1. 数据状态改为Signal:将beData从普通数组改为signal,确保数据变化时视图即时响应。
  2. 调整@defer的when条件:
    • 加入!isLoading():确保数据加载完成后才进入主块
    • 加入isError():错误状态下直接满足when条件,进入主块显示错误信息
  3. 修复loading触发逻辑:isLoading为true时,@defer不会进入主块,等待2秒后自动触发@loading块,解决超时不显示loading的问题。
  4. 优化错误处理流:catchError中返回EMPTY,避免错误数据进入subscribe导致beData被错误赋值。
  5. 移除placeholder的minimum参数:原minimum 2s强制placeholder显示至少2秒,导致loading无法及时触发,移除后loading按配置的after 2s正常显示。

内容的提问来源于stack exchange,提问作者Rocky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:13:15