Basically, I asked about reusing the data from observables yesterday, then I asked around other places as well and read some more then I figured, why not just hold an observable and manipulate the data with map
operators.
So I'm making just one HTTP request, store the observable to some variable and manipulate it there. The code works, but I'm not sure if I'm using .publishReplay(1).refCount()
correctly, or should I use connect
? Or, do I even need any of that? Also, is there any possible memory leak that could come out of this service?
Here's the code to service:
@Injectable()
export class UsersApiService {
private readonly baseUrl: string = 'https://reqres.in/api/users';
resource$: Observable<any>;
constructor(private http: HttpClient) {
this.resource$ = this.http.get<IUserDetails[]>(this.baseUrl).pipe(
tap((data) => {
console.log('"getUsers" successfully called!');
}),
map((data: any) => {
return data.data;
})
).publishReplay(1).refCount();
}
getUsers(): Observable<IUser[]> {
return this.resource$.pipe(
map((data: IUserDetails[]) => {
return <IUser[]>data.map((u) => {
return {
id: u.id,
name: `${u.first_name} ${u.last_name}`
};
});
})
);
}
getUserById(id: number): Observable<IUserDetails> {
return this.resource$.pipe(
map((data) => {
return <IUserDetails>data.find(x => x.id === id);
})
);
}
}
And the working example: http://plnkr.co/edit/3S8iKbvrrGOj9netd8sM?p=preview
Descriptionlink. Internally it counts the subscriptions to the observable and subscribes (only once) to the source if the number of subscriptions is larger than 0. If the number of subscriptions is smaller than 1, it unsubscribes from the source.
In contrast to share , shareReplay exposes a ReplaySubject to subscribers. ReplaySubject(1) is very similar to a BehaviorSubject .
RxJS share() operator is a multicasting operator which returns a new observable that shares or multicasts the original observable. As long as there is at least one subscriber, this observable will be subscribed and emitting data. When all subscribers have unsubscribed, it will unsubscribe from the source observable.
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified. A Pipeable Operator is essentially a pure function which takes one Observable as input and generates another Observable as output.
I'm not sure if I'm using .publishReplay(1).refCount() correctly
Yes, you are. You can also use shareReplay(1)
instead.
or should I use connect?
refCount()
already connects for you when the first subscriber comes along (and disconnects when all observers have unsubscribed).
do I even need any of that
If you want to hold it as an observable, yes. Otherwise you will query the backend over and over again. You could, however, of course also just memorize the last emission:
private resource: Observable<IUserDetails[]>;
constructor(http: HttpClient) {
this.http.get(/* … */).subscribe(data => this.resource = data);
}
getUserById(id: number): IUserDetails {
return this.resource.find(x => x.id === id);
}
Also, is there any possible memory leak that could come out of this service?
No, because HttpClient
completes its return observable, which means the source of your multicasted observable is disconnected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With