如何有效实现Angular Deferrable Views?解决现有实现的两大问题
解决Angular Deferrable Views的两个核心问题
问题根源分析
- 错误时卡在@placeholder:原@defer的
when条件仅判断beData是否有数据,后端返回错误时beData始终为空,导致when条件不满足,无法进入主块显示错误信息;且@defer的@error块仅处理组件加载失败(如子组件无法加载),而非数据请求错误。 - @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>
关键修改说明
- 数据状态改为Signal:将
beData从普通数组改为signal,确保数据变化时视图即时响应。 - 调整@defer的when条件:
- 加入
!isLoading():确保数据加载完成后才进入主块 - 加入
isError():错误状态下直接满足when条件,进入主块显示错误信息
- 加入
- 修复loading触发逻辑:
isLoading为true时,@defer不会进入主块,等待2秒后自动触发@loading块,解决超时不显示loading的问题。 - 优化错误处理流:catchError中返回
EMPTY,避免错误数据进入subscribe导致beData被错误赋值。 - 移除placeholder的minimum参数:原
minimum 2s强制placeholder显示至少2秒,导致loading无法及时触发,移除后loading按配置的after 2s正常显示。
内容的提问来源于stack exchange,提问作者Rocky
相关产品推荐
相关产品推荐

