RxJs / Ngrx限制指定参数的http调用

时间:2019-09-26 16:50:49

标签: angular rxjs ngrx

我通过以下方法获得了Angular服务:

  public getItem(itemId: string): Observable<IItem> {
    if (itemId== null) {
      return of(null);
    }
    return this.store.pipe(
      select(getItemFromStore(itemId)),
      tap(item=> {
        if (item=== undefined) {
          this.store.dispath(new GetItemAction({itemId: itemId}}));
        }
      }),
    );
  }

以及捕捉动作的效果:

@Effect()
public getItem$: Observable<Action> = this.actions
    .pipe(
        ofType(ActionTypes.GET_ITEM),
        map((action: GetItemAction) => action.payload),
        exhaustMap(payload => {
            return this.httpClient.get(`api/items/` + payload.itemId).pipe(
                map(item => {
                    return new GetItemSuccessAction({ itemId: payload.itemId, item });
                }),
                catchError(error => {
                    return of(new GetItemErrorAction({ error: error }));
                })
            );
        })
    );

除了我要同时请求两个不同的项目外,这一切都很好而且很花哨,exaustMap会忽略第二个项目并且永远都不会检索它。

我该怎么写,这样对同一个项目的请求只能加载一次,但是同时对两个项目的请求都可以加载?

一个例子:

This.store.dispatch(new GetItemAction({itemId: '1'});
This.store.dispatch(new GetItemAction({itemId: '1'});
This.store.dispatch(new GetItemAction({itemId: '2'});

如果所有3个动作均已分派,则应该有2个http请求,一个针对项目1,一个针对项目2。

1 个答案:

答案 0 :(得分:1)

您可以使用distinct运算符。

  

返回一个Observable,该Observable发出源Observable发出的所有项目,这些项目与之前的项目相比是不同的。

例如:

const s = new Subject();

const source = s.pipe(
  distinct(p => p.id),
  concatMap(p => of(p)) // instead of `of(p)`, call the service
);

source.subscribe(x => console.log(x));

s.next({id: 1, text: 'AAA'})
s.next({id: 1, text: 'BBB'})
s.next({id: 2, text: 'CCC'})
s.next({id: 2, text: 'DDD'})
s.next({id: 1, text: 'EEE'})
s.next({id: 4, text: 'FFF'})

日志:

{id: 1, text: "AAA"}

{id: 2, text: "CCC"}

{id: 4, text: "FFF"}

这也意味着您以后将无法获取id 1,如果您要这样做,则可以使用groupBy

const s = new Subject();

const source = s.pipe(
  groupBy(p => p.id),
  mergeMap(p => p.pipe(
      exhaustMap(p => of(p).pipe(delay(1000))),
    )
  ),
);

source.subscribe(x => console.log(x));

s.next({id: 1, text: 'AAA'})
s.next({id: 1, text: 'BBB'})
s.next({id: 2, text: 'CCC'})
s.next({id: 2, text: 'DDD'})
s.next({id: 1, text: 'EEE'})
s.next({id: 4, text: 'FFF'})

setTimeout(() => {
  s.next({id: 1, text: 'AAA'})
}, 2000)

日志:

{id: 1, text: "AAA"}

{id: 2, text: "CCC"}

{id: 4, text: "FFF"}

After 2 seconds:

{id: 1, text: "AAA"}