RxJS subscribe已弃用报错:Angular/Ionic星球大战列表代码问题
问题描述
开发Angular/Ionic星球大战角色列表页面时,调用ApiService的getStarwarsHeroes方法时,.subscribe出现划灰提示,提示该API已弃用。
相关代码
API服务代码
import { Injectable } from '@angular/core'; import {HttpClient} from '@angular/common/http'; import { Observable} from 'rxjs'; export interface ApiResult { page: number; results: any[]; total_pages: number; total_results: number; } @Injectable({ providedIn: 'root' }) export class ApiService { constructor(private http: HttpClient) {} getStarwarsHeroes(page:number =1): Observable<ApiResult> { return this.http.get<ApiResult>(`https://swapi.dev/api/people/${page}/`); } getStarwarsDetails(id:string): Observable<any>{ return this.http.get<ApiResult>( `https://swapi.dev/api/people/${id}/` ); } }
页面TS代码
import { Component, OnInit } from '@angular/core'; import { ApiService} from '../api.service'; import { InfiniteScrollCustomEvent, LoadingController} from '@ionic/angular'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { starwars:any=[]; currentPage:number= 1; constructor( private apiService:ApiService, private loadingCtrl: LoadingController ) {} ngOnInit() { this.loadStarwars(); } async loadStarwars(event?: InfiniteScrollCustomEvent) { const loading= await this.loadingCtrl.create({ message: 'Loading..', spinner: 'bubbles', }); await loading.present(); this.apiService.getStarwarsHeroes(this.currentPage).subscribe( (res) => { loading.dismiss(); this.starwars.push(...res.results); console.log(this.starwars); event?.target.complete(); if (event) { event.target.disabled = res.total_pages === this.currentPage; } }, (err) => { console.log(err); loading.dismiss(); } ); } loadMore(event: InfiniteScrollCustomEvent) { this.currentPage++; this.loadStarwars(event); } }
页面HTML代码
<ion-header [translucent]="true"> <ion-toolbar> <ion-title> StarWars Characters </ion-title> <ion-button slot="start"> <ion-menu-button menu="main-menu"></ion-menu-button> </ion-button> </ion-toolbar> </ion-header> <ion-content> <ion-card *ngFor='let item of starwars' [routerLink]="[item.id]" > <ion-card-header> <ion-card-title slot="start">{{item.name}}</ion-card-title> </ion-card-header> <ion-card-content slot="end">{{item.gender}}</ion-card-content> </ion-card> </ion-content>
解决方案
原因说明
划灰提示源于RxJS 7+版本中,subscribe(next, error, complete)这种多参数回调的调用方式被标记为弃用,官方推荐使用观察者对象形式调用subscribe,或者在Angular项目中使用async管道自动管理订阅(更优方案,可避免手动订阅的内存泄漏问题)。
方案一:改用观察者对象调用subscribe
修改loadStarwars方法中的subscribe部分,将多参数回调改为对象形式:
async loadStarwars(event?: InfiniteScrollCustomEvent) { const loading= await this.loadingCtrl.create({ message: 'Loading..', spinner: 'bubbles', }); await loading.present(); this.apiService.getStarwarsHeroes(this.currentPage).subscribe({ next: (res) => { loading.dismiss(); this.starwars.push(...res.results); console.log(this.starwars); event?.target.complete(); if (event) { event.target.disabled = res.total_pages === this.currentPage; } }, error: (err) => { console.log(err); loading.dismiss(); } }); }
方案二:使用async管道优化(推荐)
此方式无需手动调用subscribe,Angular会自动处理订阅与取消订阅,避免内存泄漏:
- 修改页面TS代码,调整数据存储与分页逻辑:
import { Component, OnInit } from '@angular/core'; import { ApiService} from '../api.service'; import { InfiniteScrollCustomEvent, LoadingController} from '@ionic/angular'; import { Observable, concat, of } from 'rxjs'; import { catchError, finalize, map, tap } from 'rxjs/operators'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { starwars$: Observable<any[]>; private allResults: any[] = []; currentPage: number = 1; private isLastPage = false; constructor( private apiService: ApiService, private loadingCtrl: LoadingController ) {} ngOnInit() { this.loadStarwars(); } async loadStarwars(event?: InfiniteScrollCustomEvent) { if (this.isLastPage) { event?.target.complete(); return; } const loading = await this.loadingCtrl.create({ message: 'Loading..', spinner: 'bubbles', }); await loading.present(); const pageData$ = this.apiService.getStarwarsHeroes(this.currentPage).pipe( tap(res => { this.isLastPage = res.total_pages === this.currentPage; this.allResults.push(...res.results); }), map(() => this.allResults), catchError(err => { console.log(err); return of(this.allResults); }), finalize(() => { loading.dismiss(); event?.target.complete(); if (event) { event.target.disabled = this.isLastPage; } }) ); this.starwars$ = this.currentPage === 1 ? pageData$ : concat(this.starwars$, pageData$); this.currentPage++; } loadMore(event: InfiniteScrollCustomEvent) { this.loadStarwars(event); } }
- 修改页面HTML代码,使用
async管道:
<ion-header [translucent]="true"> <ion-toolbar> <ion-title> StarWars Characters </ion-title> <ion-button slot="start"> <ion-menu-button menu="main-menu"></ion-menu-button> </ion-button> </ion-toolbar> </ion-header> <ion-content> <ion-card *ngFor='let item of starwars$ | async' [routerLink]="[item.id]" > <ion-card-header> <ion-card-title slot="start">{{item.name}}</ion-card-title> </ion-card-header> <ion-card-content slot="end">{{item.gender}}</ion-card-content> </ion-card> </ion-content>
内容的提问来源于stack exchange,提问作者Stefan Stahuber
相关产品推荐
相关产品推荐

