简体   繁体   中英

Store API data in subject before subscribing to Observable - Angular 10

I'm trying to store data returned from an API inside a behaviour subject with the next method and I'd like to do this before subscribing to the observable.

Let's say I have service which has this function to retrieve some data from an API:

getData(): Observable<Data> {
    return this.http.get(APIURL);
}

Now before subscribing to getData() I'd like to save what has been returned from the API in a subject. I managed to achieve this with the tap() operator, but by reading the documentation, tap should be used for side effects and in this case it doesn't look like one. So what I did was something like this:

getData(): Observable<Data> {
        return this.http.get(APIURL)
               .pipe(tap(data => this.subject.next(data));
}

I'm doing this so I can have some sort of cache so that I don't have to call the API again and do some manipulation on that data when it gets updated. For instance let's say I add an element to that data with an update query, now I can update the previous data stored in the subject so everything is up to date. Only by refreshing the page I would call the API again.

What is unclear to me is the use of the tap operator, is it fine to use it like this or are there better alternatives for what I'm trying to do?

If I understand right, you can just check, that you have some data in Subject

subject = new BehaviorSubject<any>(null);

getData(): Observable<Data> {
   if (subject.getValue()) {
      return of(subject.getValue());
   }
   return this.http.get(APIURL)
        .pipe(tap(data => this.subject.next(data));
}

Here is a CodeSandbox that shows one way to manage your cache request flows in the case where you don't use a state management library.

The essence of the demo is the following

 interface IArticle { title: string; content: string; } @Injectable({ providedIn: "root" }) export class HttpDemoCache { // You need a variable where to store the data cachedArticleResponse$: BehaviorSubject<IArticle[]> = new BehaviorSubject([]); ... loadArticles(someQuery) { // You need a method that fetches the data from the BE this.httpClient.get(...).subscribe((x) => { this.cachedArticleResponse$.next(x); }); } updateArticles(newArticle: IArticle) { // You need a update method to send the new enttity to the back-end + update your cached version this.http.post(...., {newArticle}).pipe( switchMap(response => this.cachedArticleResponse$.pipe( take(1), tap(cachedArtilces => this.cachedArticleResponse$.next([...cachedArticles, newArticle])) ) ) ).subscribe() }); } }

Pretty much with this solution you are creating your own state-management solution which responsibility will be to take care of all cahce/fetch/upload/delete logic.

The benefit of this solution is that you have way more control over what is happening than when you are fetching the data directly in the components.

** Side-note: keep in mind that this is a verry brief example of a concept, not a detailed solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM