Reputation: 64
I have two components that both use data retrieved from an API endpoint over http. I want to cache the response from the API endpoint so only one http request is made, but I also want to be able to clear the cache when I know data has changed so that the two components are updated via their original subscriptions.
I can get caching to work so only one http request is made by using publishReplay(1)
. But I can't find a way to invalidate the cache with that method.
I've tried creating my own observable and calling next()
when I don't already have a cached version of the data, but I can't figure out how I might redefine the observer function so it returns different data when I invalidate the cache.
class ApiService {
private user$: Observable<User>;
...
getUser() {
if (!this.user$)
this.user$ = this.http.get<User>(`${apiUrl}users/me`).pipe(shareReplay(1));
return this.user$;
}
invalidateUserCache() {
// do what? Can't assign a new observable to this.user$ because
// any components that have already subscribed won't be notified
// of the updates
}
}
class UserProfileComponent implements OnInit {
user: User;
...
ngOnInit() {
this.api.getUser().subscribe(user => this.user = user);
}
updateUser() {
this.api.updateUser(someData).subscribe(response => {
this.api.invalidateUserCache();
// Since cache has been invalidated, I want this to
// make a new http request and notify other components
// that have subscribed.
this.api.getUser().subscribe(user => this.user = user);
}
}
}
class MenuComponent implements OnInit {
user: User;
...
ngOnInit() {
this.api.getUser().subscribe(user => this.user = user);
}
}
The above code caches the User object so only one http request is made, but if UserProfileComponent
updates the user, MenuComponent
is not updated with the new user.
Upvotes: 2
Views: 1697
Reputation: 64
At Jeyenth's suggestion of using BehaviorSubject, I came up with this:
class ApiService {
private _user: BehaviorSubject<User>;
...
getUser() {
if (!this._user) { // we haven't already requested the current user
this._user = new BehaviorSubject(null);
this.http.get<User>(`${apiUrl}users/me`).subscribe(user => this._user.next(user));
}
return this._user;
}
refreshUser() {
this.http.get<User>(`${apiUrl}users/me`).subscribe(user => this._user.next(user));
}
}
It works perfectly. Thanks Jeyenth!
Upvotes: 1
Reputation: 314
If you want to update the cache, you simply set the reference value this.user$
to null. Then when the method getUser()
is executed again, it will run a new server request which then updates the previous stored cache.
clearCache() {
this.user$= null;
}
Upvotes: 0