0

Say I have an angular component that displays a list of items:

<app-item *ngFor="let item of items"></app-item>

Say that an item looks like this:

interface Item {
  userId: number;
  name: string;
}

and ItemComponent wants to display an item with the following HTML:

<p>{{username$ | async}} has item "{{item.name}}"</p>

And in the component's typescript file, these are the relevant parts:

@Input() item: Item;

username$: Observable<string>;

ngOnInit() {
  this.store.dispatch(new LoadUser({id: item.userId}));

  this.username$ = this.store$.select(selectUser, {id: item.userId}).pipe(
    filter(user => !!user),
    map(user => username)
  );
}

Now, if I have lots of items by the same user, every time an <app-item> is rendered, that will trigger a new API call to get the user (via the dispatched action and relative effect, omitted for brevity), even if the user is already in the store.

To obviate this, I modified my effect to first check if a user in the store, and if it, return it, otherwise fetch a new one from the API.

But this only works for requests that are happening later in time: in the scenario above, they all start at about the same time (before the first API request returns a value), so they are all run via the API.

I feel like this would be a common problem... what is the proper way to deal with it?

Thanks!

Salvatore Iovene
  • 2,064
  • 1
  • 17
  • 31
  • Check [this](https://stackoverflow.com/questions/50864978/angular-rxjs-6-how-to-prevent-duplicate-http-requests) SO question. – Eldar Sep 29 '21 at 12:24

2 Answers2

0

Use the exhaustMap operator. This will cancel incoming requests when there's one pending.

timdeschryver
  • 14,415
  • 1
  • 19
  • 32
0

You could try using shareReplay() in your service file where the HTTP call is being made. With that, you can share your observable response.

import { shareReplay } from 'rxjs/operators';

export class AService {
  getUsers(id: number): Observable<SomeInterface> {
     return this.http.get<SomeInterface>(`url/${id}`).pipe( 
       shareReplay()
     )
  }
}
Andres2142
  • 2,622
  • 2
  • 14
  • 19