Caching data in RxJS is a handy feature that can increase the responsiveness of your site (or at least it will feel that way to your users). And on some devices and in some scenarios, saving that extra HTTP call is really important. So when data doesn’t change frequently it makes a lot of sense to cache the data that came back and share it in multiple places, or when the user leaves the route and goes back to the same page. To read more about my current favorite way of doing this, read my last article on caching and refreshing data using RxJS here. In that article, you’ll learn how to create an observable that will share the HTTP call data with new subscribers, but after a user defined amount of time, the call will be re-made so that the data is fresh. Here’s what that looks like though, as a refresher for those that have already read that article:

let returnObs$: Observable<any>;

const createReturnObs = (obs: Observable<any>, time: number, bufferReplays: number) =>
	(returnObs$ = obs.pipe(shareReplay(bufferReplays, time)));

export function renewAfterTimer(obs: Observable<any>, time: number, bufferReplays: number = 1) {
	return createReturnObs(obs, time, bufferReplays).pipe(
		first(null, defer(() => createReturnObs(obs, time, bufferReplays))),
		mergeMap(d => (isObservable(d) ? d : of(d))),
	);
}

This function creates an observable that caches the data for the user defined amount of time, and then if a new subscriber comes after it “expires”, the HTTP call is made again and the cached data is replaced.

That function works great, and the new function that I’m going to show you today uses the above, but adds a little bit more flexibility.

Flexibility in Caching Data

The above function is great for data that doesn’t require parameters, like a list of items or something like that. It’s perfect in that case because you can just create the observable and know that every time someone asks for that data it will be the same. But what if you want to get the details of an item and cache it?

In my case, we have some data that needs to be loaded for the current month. Most of the time, they’ll only want the current month, so we want to cache the response. But every now and then they’ll go back to a previous month to view that data. In that case, we want to replace the cache with our new data. What I didn’t want to do, though, was have a big list of observables that I was trying to keep track of, creating a new one each time the function was called. That’s fine, and might work, but I wanted a single observable in my service that was passed around.

Here’s how I did this:

export class SwapiService {
	constructor(private _http: HttpClient) {}

	private lastCharacterQueried: string;
	private steps$: Observable<any>;

	getCharacter(characterId: string) {
		if (characterId !== this.lastCharacterQueried) {
			this.steps$ = renewAfterTimer(this._http.get(`https://swapi.co/api/people/${characterId}`), 10 * 1000);
			this.lastCharacterQueried = characterId;
		}
		return this.steps$;
	}
}

In this example, I’m using the Star Wars API (swapi.co) to get the details of a single character. To do that, I call the getCharacter function and pass an ID into the function. I check to see if the ID is the same as the last one that was passed in. If so, I just return the observable I already created. If now, I create a new observable that will renew after 10 seconds, then save the character ID and return the observable.

#angular #rxjs #programming

Flexible Caching and Refreshing with RxJS in Angular
4.90 GEEK