Angular Universal中父组件总是刷新:如何仅调用一次分类接口?
解决Angular Universal主组件重复调用分类接口的问题
方案一:利用单例服务缓存数据(推荐)
将分类数据的请求逻辑封装到全局单例服务中,通过缓存机制确保接口仅调用一次。服务在应用生命周期内是单例,无论组件是否重建,都能复用已获取的数据。
创建分类服务:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { tap } from 'rxjs/operators'; // 定义分类数据结构 interface Category { id: number; name: string; } @Injectable({ providedIn: 'root' }) export class CategoryService { // 私有变量存储缓存数据 private cachedCategories: Category[] | null = null; constructor(private http: HttpClient) {} getCategories(): Observable<Category[]> { // 如果已有缓存,直接返回缓存数据的Observable if (this.cachedCategories) { return of(this.cachedCategories); } // 无缓存时调用接口,并缓存返回结果 return this.http.get<Category[]>('/api/categories').pipe( tap(categories => { this.cachedCategories = categories; }) ); } }
在主组件中使用:
import { Component } from '@angular/core'; import { CategoryService } from './category.service'; @Component({ selector: 'app-main', template: ` <nav> <a *ngFor="let category of categories$ | async" [routerLink]="['/category', category.id]"> {{ category.name }} </a> </nav> <router-outlet></router-outlet> ` }) export class MainComponent { // 直接通过服务获取数据,async pipe自动处理订阅与销毁 categories$ = this.categoryService.getCategories(); constructor(private categoryService: CategoryService) {} }
方案二:修正路由配置,避免主组件重复重建
检查你的路由配置,确保主组件作为父路由的容器,子路由嵌套在其children数组中。如果每个子路由都单独指定主组件,会导致每次路由切换时主组件被销毁重建,进而重复触发ngOnInit。
正确的路由配置示例:
import { Routes } from '@angular/router'; import { MainComponent } from './main.component'; import { HomeComponent } from './home.component'; import { CategoryComponent } from './category.component'; export const routes: Routes = [ { path: '', component: MainComponent, // 主组件作为父路由容器 children: [ { path: 'home', component: HomeComponent }, { path: 'category/:id', component: CategoryComponent }, { path: '', redirectTo: 'home', pathMatch: 'full' } ] } ];
方案三:组件内标记加载状态
在主组件中添加一个状态变量,标记数据是否已加载,仅在首次进入时调用接口。这种方法适用于主组件不会被销毁的场景(所有路由都是其子路由)。
import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; interface Category { id: number; name: string; } @Component({ selector: 'app-main', template: ` <nav> <a *ngFor="let category of categories" [routerLink]="['/category', category.id]"> {{ category.name }} </a> </nav> <router-outlet></router-outlet> ` }) export class MainComponent implements OnInit { categories: Category[] = []; private isLoaded = false; // 标记是否已加载数据 constructor(private http: HttpClient) {} ngOnInit(): void { if (!this.isLoaded) { this.loadCategories(); this.isLoaded = true; } } private loadCategories(): void { this.http.get<Category[]>('/api/categories').subscribe(categories => { this.categories = categories; }); } }
内容的提问来源于stack exchange,提问作者Faris Švrakić
相关产品推荐
相关产品推荐

