问题描述
我有几个订阅我的数据服务的组件,它们都工作正常。但是在我的组件之一中,我尝试订阅两次(在ngOnInit和ngAfterViewInit内部),但这不起作用。这是组件:
ngOnInit() {
this.dataService.data$.pipe(first()).subscribe(subscribetoData => {
this.title = this.dataService.getData("...");
this.anotherService.getData
.subscribe(another => {
this.data = data;
},...
});
}
ngAfterViewInit() {
this.dataService.data$.pipe(first()).subscribe(subscribetoData => {
let options = {
data: {
}
...
{
title: this.dataService.getData("...");
},...
};
...
});
}
如果我从ngOnInit删除订阅,则ngAfterViewInit可以正常工作,否则它将失败。那么,有没有办法从同一组件中同时订阅两次或多次?
这是数据服务:
private dataSource = new ReplaySubject(1);
data$ = this.dataSource.asObservable();
loadData(... : void) {
if (sessionStorage["data"] == null {
this.http.request(...)
.map((response: Response) => response.json()).subscribe(data => {
...
sessionStorage.setItem("data",JSON.stringify(this.data));
this.dataSource.next(this.data);
...
});
} else {
this.dataSource.next(this.data);
}
}
getData(... : string){
...
}
解决方法
代码中的双重订阅没有问题-可能您遇到了一些异步代码问题。浏览器足够快,可以快速浏览组件的生命周期并快速调用ngOnInit
和ngAfterViewInit
。它们几乎都将同时执行,并且闪电般快速-绝对比http调用快。在这种情况下,在您的ngOnInit
的订阅中,您有另一个可能在ngAfterViewInit
之后执行的调用(尽管我不确定)。
下面是一个示例,该示例显示在单个组件中进行双重订阅可以工作: https://stackblitz.com/edit/double-subscribe?file=src/app/app.component.ts
尝试将逻辑重构为更连续的:如果必须在ngAfterViewInit
中的所有异步代码完成后 执行ngOnInit
,请保存{ {1}}的链在变量中的某个位置;如果您的ngOnInit
不关心ngAfterViewInit
,请尝试避免访问相同的变量,尤其是ngOnInit
。
也请尝试避免嵌套this.data
-可以将其替换为subscribe
/ switchMap
:
flatMap
要重构您的ngOnInit() {
this.dataService.data$.pipe(
first(),tap(data => this.title = this.dataService.getData(data)),// note that this should be synchronous
switchMap(data => {
// another asynchronous call here
return this.anotherService.getData(data)
})
).subscribe(finalData => {
this.data = finalData
}
以在 ngAfterViewInit
之后执行,请执行以下操作:
ngOnInit
通常,您会想想为什么甚至需要onInitData$: Observable<any>;
ngOnInit() {
this.onInitData$ = this.dataService.data$.pipe(
first(),// note that this should be synchronous
switchMap(data => {
// another asynchronous call here
return this.anotherService.getData(data)
}),shareReplay(1) // shareReplay(1) is important to avoid doing double http requests per subscribe
);
this.onInitData$.subscribe(data => console.log('data from ngOnInit',data));
}
ngAfterViewInit() {
this.onInitData$.pipe(switchMap(thatData) => {
// will be executed only AFTER the ngOnInit is done
return this.dataService.data$.pipe(first()).subscribe(subscribeToData => {
let options = {
data: {
}
...
{
title: this.dataService.getData("...");
},...
};
...
});
}).subscribe(dataFromAfterViewInit => {})
}
?您想通过在ngAfterViewInit
/ onInit
之间拆分这些调用来实现什么?他们为什么要访问组件中的相同数据?