需求:基于Signal的多Observable异步操作状态跟踪工具(支持OnPush)
基于Signal的异步请求状态跟踪方案
实现思路
搭建一个全局状态管理服务,用Angular Signal跟踪所有动物相关请求的加载状态,同时包装原AnimalService的请求方法,自动处理状态更新。这样任何组件都能直接获取全局或单个请求的加载状态,完美适配OnPush变更检测策略。
1. 先定义状态类型
统一规范请求标识和状态结构:
type AnimalRequestKey = 'cats' | 'dogs' | 'chickens'; interface AnimalLoadingState { [key in AnimalRequestKey]: boolean; }
2. 创建全局状态管理服务
这个服务是核心,负责维护状态信号、包装请求方法:
import { Injectable, inject, signal, computed } from '@angular/core'; import { AnimalService } from './animal.service'; import { finalize, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AnimalLoadingStateService { private readonly animalService = inject(AnimalService); // 存储单个请求的加载状态 private readonly loadingStates = signal<AnimalLoadingState>({ cats: false, dogs: false, chickens: false }); // 计算信号:全局是否有动物请求在加载 readonly isAnyAnimalLoading = computed(() => { const states = this.loadingStates(); return Object.values(states).some(isLoading => isLoading); }); // 获取单个请求的加载状态 getLoadingState(key: AnimalRequestKey) { return computed(() => this.loadingStates()[key]); } // 通用包装方法:自动处理状态更新 private wrapRequest<T>(key: AnimalRequestKey, request$: Observable<T>): Observable<T> { this.loadingStates.update(state => ({ ...state, [key]: true })); return request$.pipe( finalize(() => { this.loadingStates.update(state => ({ ...state, [key]: false })); }) ); } // 暴露包装后的请求方法 fetchCats() { return this.wrapRequest('cats', this.animalService.fetchCats()); } fetchDogs() { return this.wrapRequest('dogs', this.animalService.fetchDogs()); } fetchChickens() { return this.wrapRequest('chickens', this.animalService.fetchChickens()); } }
3. 在OnPush组件中使用
组件A(触发请求)
import { Component, inject } from '@angular/core'; import { AnimalLoadingStateService } from './animal-loading-state.service'; import { ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'app-component-a', template: ` <button (click)="loadCats()">加载猫数据</button> <button (click)="loadDogs()">加载狗数据</button> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class ComponentA { private readonly loadingStateService = inject(AnimalLoadingStateService); loadCats() { this.loadingStateService.fetchCats().subscribe(data => { // 处理猫数据逻辑 }); } loadDogs() { this.loadingStateService.fetchDogs().subscribe(data => { // 处理狗数据逻辑 }); } }
组件B(显示全局加载状态)
import { Component, inject } from '@angular/core'; import { AnimalLoadingStateService } from './animal-loading-state.service'; import { ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'app-component-b', template: ` <div *ngIf="isLoading()" class="loading-spinner">加载中...</div> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class ComponentB { private readonly loadingStateService = inject(AnimalLoadingStateService); // 直接绑定计算信号,OnPush会自动响应变更 isLoading = this.loadingStateService.isAnyAnimalLoading; }
可选扩展
- 可以给状态结构添加
error字段,跟踪请求错误状态 - 若要支持更多请求,只需扩展
AnimalRequestKey和对应的请求方法即可
内容的提问来源于stack exchange,提问作者Francesco Borzi
相关产品推荐
相关产品推荐

