In my service, I have integrated the sharereplay from RXJS. but navigating between pages, share replay not considered. each time my api updated from remote. any one help me to understand the issue? show me the correct way to implement the same?
service code:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, map, shareReplay } from 'rxjs/operators';
export interface PostProps {
userId: number;
id: number;
title: string;
body: string;
processed: string;
}
@Injectable()
export class PersonnelDataService {
list$: Observable<PostProps[]>;
private URL = 'https://jsonplaceholder.typicode.com/posts';
constructor(private http: HttpClient) {}
fetchPersonnelList() {
if (!this.list$) {
this.list$ = this.http.get<PostProps[]>(this.URL).pipe(
map((response: PostProps[]) => response),
shareReplay(1),//not works
catchError(async (error) => this.handleError(error))
);
}
return this.list$;
}
handleError(error) {
throwError(error);
}
}
component:
ngOninit(){
this.personalDataService.fetchPersonneList();
this.personnelList$ = this.personnelDataService.list$
}
I updated the code like this:
this.list$ = this.http.get<PostProps[]>(this.URL).pipe( shareReplay(1));
I am getting data. but still when I navigate to child page, getting new api call.?!
CodePudding user response:
That's not how it works.
By assigning a new value to your variable, you're disconnecting your components from listening to the observable, and you create potential memory leaks.
Use subjects instead.
private _list = new BehaviorSubject<PostProps[]>([]);
public list$ = this._list.asObservable();
// ...
fetchPersonnelList() {
return this.http.get<PostProps[]>(this.URL).pipe(
tap(list => this._list.next(list)),
catchError(async (error) => this.handleError(error)),
);
}
CodePudding user response:
The problem can finally be seen in your CodeSandbox example. your problem is not, that shareReplay
is not working.
You actual problem is that in your component, you add the following: providers: [PostService]
. Basically you are telling Angular to instantiate a new service each time the component is constructed. Once you navigate to another route (which is not a child route as you stated) the component is destroyed and reinstantiated once you click the back button. Therefore you have two different services with different observables. This will lead to a retriggering of the HTTP call.
Once I remove the providers array from component level and either
- define the service to be available at root level like
@Injectable({providedIn: 'root'})
export class PostService {
- or add the service to the providers array of your module
The second call is gone. The reason is that only one instance of the service will be instantiated.