问题描述
Demo在我的应用程序中,我正在使用服务进行通信
import {Injectable} from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { TransferModel } from '../models/transfer';
@Injectable()
export class TransferService{
constructor(){}
private paramSource = new BehaviorSubject(new TransferModel());
getData = this.paramSource.asObservable();
setData(param:TransferModel) { this.paramSource.next(param)}
}
我的问题是,当我转到组件时,它运作良好,但在页面中也发送其他页面请求。我的意思是例如我在Courses.component
constructor(private transferService:TransferService,private dataService:DataService,sessionService:SessionService,private router:Router) {
this.transferService.getData.subscribe(x=>{
this.transfer=x; if(!this.transfer.ExamId || this.transfer.ExamId<=0){ this.router.navigateByUrl("/home");return;}
this.dataService.Post(URLS.url.coursePage.getCourses,{Id:this.transfer.ExamId}).subscribe(elem=>{
this.courses=elem;
});
});
}
当我单击一门课程时,上面的
goToSubject(id){
this.transfer.CourseId=id;
this.transferService.setData(this.transfer);
this.router.navigateByUrl("/subjects");
}
constructor(private transferService:TransferService,private router:Router) {
this.transferService.getData.subscribe(x=>{
this.transfer=x; if(!this.transfer.ExamId || this.transfer.ExamId<=0){ this.router.navigateByUrl("/home"); }
this.dataService.Post(URLS.url.subjectPage.getSubjects,{ExamId:this.transfer.ExamId,CourseId:this.transfer.CourseId}).subscribe(elem=>{
this.subjects=elem;
});
});
}
,但是这里也有另一个页面的请求调用,例如图像。 我需要每个页面仅发送一个请求。
我该如何解决这个问题?
解决方法
我假设由于transferService.getData()
返回了一个Subject
(您正在订阅,并且可能没有在任何地方取消订阅组件onDestroy
上的),所以这些订阅仍然有效,并且调用。
您的goToSubject()
会调用this.transferService.setData(this.transfer);
,该调用基本上会调用所有订阅。
您将需要保留 Subscription
时返回的subscribe
并在unsubscribe()
上致电ngOnDestroy()
subscription: Subscription;
constructor(...){
this.subscription = this.transferService.getData.subscribe(x=>{
...
});
}
ngOnDestroy() {
if(this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
}
如果您的组件上有多个subscribe()
,也许您想利用某种takeUntil之类的自我订阅实现方式
注意:默认情况下,Angular HttpClient订阅是自动退订的,因此在调用unsubscribe()
时不需要调用httpClient.get().subscribe()
。对于其他所有内容,您都需要致电unsubscribe()
。
更新:
查看了您提供的stackblitz演示后,可以确认问题出在transferService.getData()
主题上。但是,即使取消订阅ngOnDestroy()
,它仍然会调用,因为在重定向之前您有this.transferService.setData(..)
,这实际上会调用transferService.getData().subscribe(...)
。
要解决此问题而无需进行重大重构,您必须将其设置为“仅预订一次”或“在调用预订后立即自动取消预订”。这使我们回到了takeUntil
。
courses.component和subjects.component中的
constructor() {
const subj: Subject<boolean> = new Subject<boolean>();
this.transferService.getData
.pipe(takeUntil(subj))
.subscribe((result) => {
subj.next(true);
});
}
更新2: