Angular中API请求完成前避免显示404组件的解决方案
Angular组件等待API加载完成再渲染视图的解决方案
问题根源
当前代码中,组件初始化时salesData默认是undefined,API请求需要1秒才能返回数据,这会直接触发@else分支显示app-not-found组件。核心问题是没有区分「数据正在加载」和「无数据/请求失败」两种状态。
解决方案
方法1:新增加载状态标记(最直接的修改)
在组件中添加一个加载状态变量,用来控制加载过程中的显示逻辑,避免过早渲染错误组件。
修改业务逻辑代码:
isLoading = true; // 新增加载状态标记 getAds(n:string) { this.isLoading = true; // 请求开始时标记为加载中 const request$ = n.includes("sales") ? this.service.getAds() : this.service.getRentsAds(); request$.subscribe({ next: (response) => { this.salesData = response; this.records = this.salesData.length; this.pageRecords = this.salesData.slice(0, this.recordsPerPage); this.totalPages = this.records / this.recordsPerPage; // 替代原for循环,更简洁的分页数组生成方式 this.numberOfPages = Array.from({length: Math.ceil(this.totalPages)}, (_, i) => i + 1); }, complete: () => { this.isLoading = false; // 请求完成(无论成功失败)取消加载状态 }, error: () => { this.isLoading = false; // 请求失败也要取消加载状态 // 可在此添加错误提示逻辑,比如设置errorStatus变量 } }); }
修改组件模板:
<!-- 加载中显示占位内容,比如骨架屏或加载动画 --> @if(isLoading) { <div class="flex justify-center items-center h-96"> <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-500"></div> </div> } @else if(salesData) { <!-- 原有的数据渲染内容 --> <div class="flex flex-col space-y-4 max-w-md mx-auto bg-white shadow-md overflow-hidden md:max-w-6xl"> @for (i of pageRecords; track i.id) { <!-- 每条数据的渲染代码 --> } </div> @if (totalPages > 0) { <!-- 分页组件代码 --> } } @else { <!-- 仅当请求完成且无数据时,才显示错误组件 --> <app-not-found /> }
方法2:使用AsyncPipe(RxJS最佳实践)
通过将API请求转为Observable,配合Angular的AsyncPipe自动处理订阅和状态,无需手动管理加载状态和订阅取消。
修改业务逻辑代码:
salesData$!: Observable<any[]>; // 定义Observable变量 getAds(n:string) { this.salesData$ = n.includes("sales") ? this.service.getAds() : this.service.getRentsAds(); // 在管道中处理分页逻辑,简化组件代码 this.salesData$ = this.salesData$.pipe( tap(response => { this.records = response.length; this.pageRecords = response.slice(0, this.recordsPerPage); this.totalPages = this.records / this.recordsPerPage; this.numberOfPages = Array.from({length: Math.ceil(this.totalPages)}, (_, i) => i + 1); }) ); }
修改组件模板:
<!-- AsyncPipe会自动等待Observable发出数据,数据未返回前不会进入else分支 --> @if (salesData$ | async; as salesData) { <!-- 原有的数据渲染内容 --> <div class="flex flex-col space-y-4 max-w-md mx-auto bg-white shadow-md overflow-hidden md:max-w-6xl"> @for (i of pageRecords; track i.id) { <!-- 每条数据的渲染代码 --> } </div> @if (totalPages > 0) { <!-- 分页组件代码 --> } } @else { <!-- 数据加载中显示的内容 --> <div class="flex justify-center items-center h-96"> <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-500"></div> </div> }
方法3:使用路由Resolve守卫(预加载数据)
如果希望进入组件前就完成数据加载,可以使用Angular的路由Resolve守卫,确保组件激活时数据已经准备就绪。
1. 创建Resolve守卫:
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { YourService } from './your.service'; @Injectable({ providedIn: 'root' }) export class AdsResolver implements Resolve<any[]> { constructor(private service: YourService) {} resolve(route: ActivatedRouteSnapshot): Observable<any[]> { const type = route.paramMap.get('type') || 'sales'; // 从路由参数获取数据类型 return type.includes('sales') ? this.service.getAds() : this.service.getRentsAds(); } }
2. 配置路由:
const routes: Routes = [ { path: 'ads/:type', component: YourComponent, resolve: { salesData: AdsResolver } // 指定Resolve守卫 } ];
3. 在组件中获取预加载的数据:
import { ActivatedRoute } from '@angular/router'; constructor(private route: ActivatedRoute) {} ngOnInit() { this.salesData = this.route.snapshot.data['salesData']; // 处理分页逻辑... }
这种方式下,组件初始化时已经有数据,不会出现加载过程中的错误组件显示。
内容的提问来源于stack exchange,提问作者Oscar Plumariega
相关产品推荐
相关产品推荐

