这可能是一个菜鸟问题,但我可以在上面找到参考。
我有两个放置在不同位置的组件,每个组件都使用Service查询一个端点并获取一些数据(例如,用户个人资料)。
该服务返回一个可观察对象,我需要该可观察对象是唯一的,或者至少要发出一个唯一的请求。
// Service, shared across multiple components
@Injectable()
export class SomeService {
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
share() // is this right ?
);
}
}
// Component requesting data
@Component({ selector: '...', ... })
export class FirstComponent implements OnInit {
constructor(private _service: SomeService) { }
ngOnInit() {
this._service.getData().subscribe(
data => {
console.log(data);
}
);
}
}
// Another component requesting the same data
@Component({ selector: '...', ... })
export class SecondComponent implements OnInit {
constructor(private _service: SomeService) { }
ngOnInit() {
this._service.getData().subscribe(
data => {
console.log(data);
}
);
}
}
该服务正常工作并获取数据,但是请求发送了两次,我只希望发送一个请求。组件同时处于活动状态(假设一个在屏幕的顶部,第二个在屏幕的底部)。因此,他们会同时发出请求。
服务是否只能发送一个请求?
顺便说一句,第一个请求的状态为200,第二个状态为304。
谢谢。
可能的解决方案
到目前为止,我通过添加Service变量进行管理
private _observable: Observable<DataModel>;
然后在获取数据时
getData(): Observable<DataModel> {
if (!this._observable) {
this._observable = this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
// HERE IS THE TRICK
publishLast(),
refCount()
)
}
return this_observable;
}
诀窍是使用publishLast和refCount
有什么更好的方法/想法吗?
答案 0 :(得分:1)
看看我的库ngx-rxcache。简化了状态管理。
https://github.com/adriandavidbrand/ngx-rxcache
@Injectable()
export class SomeService {
private dataCache = this.cache.get<DataModel>({
id: 'some uniquie id',
load: true,
construct: () => this.http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response))
)
});
data$ = this.dataCache.value$;
constructor(cache: RxCacheService, http: HttpClient) {}
}
然后您可以使用来访问服务上的数据
this.service.data$;
https://medium.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb
答案 1 :(得分:0)
您可以使用forkJoin
运算符轻松地将您的请求分组为一个Observable,然后在完成所有请求后就将其解析
这是一个例子
public requestDataFromMultipleSources(): Observable<any[]> {
let response1 = this.http.get(requestUrl1);
let response2 = this.http.get(requestUrl2);
let response3 = this.http.get(requestUrl3);
// Observable.forkJoin (RxJS 5) changes to just forkJoin() in RxJS 6
return forkJoin([response1, response2, response3]);
}
在您的示例中,您应该在父组件中发出请求。然后将结果注入子组件
答案 2 :(得分:0)
您可以改用 shareReplay ,这将从所有订阅者观察源重播事件,并确保仅共享最后一个结果
shareReplay(1)
因此您的代码将如下所示
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
shareReplay(1)
);
}
答案 3 :(得分:0)
我发现以下模式可以有效地做到这一点:
@Injectable()
export class SomeService {
myDataObservable$: Observable<DataModel>;
constructor( ) {
this.myDataObservable$ = this.getData().pipe(shareReplay());
}
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response))
);
}
}
在这种模式下,在至少一个组件中的myDataObservable $上调用subscription之前,不会发送任何HTTP请求。在第一个组件调用了subscribe之后,所有后续的subscription将使用已经存在的值,因此您不会有多个http请求。