【问题标题】:Angular/NGRX - prevent duplicate requests with same parametersAngular/NGRX - 防止具有相同参数的重复请求
【发布时间】:2020-03-26 22:44:45
【问题描述】:

假设我有一个显示电影演员列表的组件。 该组件在初始化时分派一个操作以获取参与者列表。

actors.component.ts

@Input() filter; // some filter applied to the data, like display only male actors for example

ngOnInit() {
    this.store.dispatch(getActors({movieId: this.movieId}));
}

如您所见,此组件有一个过滤器,将应用于数据。

API URL 如下所示:/movies/movieId/actors

现在我可以在一页上有多个组件。为简单起见,假设我们有 3 个组件:C1、C2 和 C3。

C1 和 C2 都需要来自同一端点的数据:/movies/1/actors,但每个组件以不同的方式过滤数据。 C1 只显示男演员,C2 只显示女演员。

C3 向 /movies/2/actors 发出请求(如您所见,与 C1 和 C2 相比,它具有不同的 movieId)。

问题是,在这种情况下,将发出 3 个请求:

/movies/1/actors
/movies/1/actors
/movies/2/actors

如您所见,有一个请求被重复,这就是问题所在。最后,我只想发出 2 个请求:

/movies/1/actors
/movies/2/actors

这是对应的效果类:

actors.effects.ts

getActors$ = createEffect(() => this.actions$.pipe(
    ofType(getActors),
    mergeMap((payload) => this.actorsService.getAll({movieId: payload.movieId})
      .pipe(
        map(actors => ({ type: '[Actors API] Actors Loaded Success', payload: actors })),
        catchError(() => EMPTY)
      ))
    )
  );

还有一个reducer,它以如下形式将数据保存在store中:

{
    movieActors: [
        {movieId: 1: actors: [...]}
    ]
}

同样,问题是如何防止相同的请求被发出两次。

一种解决方案是检查存储是否已存在数据。所以效果类看起来像这样:

getActors$ = createEffect(() => this.actions$.pipe(
    ofType(getActors),
    withLatestFrom(action =>
        of(action).pipe(
            this.store.pipe(select(selectMovieActors(movieId: {action.movieId})))
        )
    ),
    filter(([{payload}, actors]) => !!actors
    mergeMap((payload) => ...

从上面的示例中,C1 和 C2 将大致同时调度 getActors 操作。效果将为 C1 运行并发出请求,然后相同的效果将立即为 C2 运行并发出新的请求,因为来自第一个请求的数据尚未到达。这就是为什么我不能使用这个解决方案。

另一种解决方案是使用exhaustMap:

getActors$ = createEffect(() => this.actions$.pipe(
    ofType(getActors),
    exhaustMap((payload) => this.actorsService.getAll({movieId: payload.movieId})
      .pipe(
        map(actors => ({ type: '[Actors API] Actors Loaded Success', payload: actors })),
        catchError(() => EMPTY)
      ))
    )
  );

如果我要使用这个解决方案,那么只会发出一个请求:/movies/1/actors。第二个请求:/movies/2/actors 将被丢弃。

我已经寻找解决方案,但它们似乎不适用于我的特殊情况。我只想在有另一个请求时才阻止请求,但在我的情况下使用相同的参数(movieId)。如果有对同一端点的请求,但 id 不同,则应发出新请求。

编辑忘了说,每个组件都有一个刷新按钮,它将再次调度 getActors({movieId: this.movi​​eId}) 动作。

【问题讨论】:

    标签: angular rxjs ngrx


    【解决方案1】:

    使用您的解决方案 2,您可以使用 distinct() 添加另一个唯一 ID 检查

    getActors$ = createEffect(() => this.actions$.pipe(
        ofType(getActors),
        withLatestFrom(action =>
            of(action).pipe(
                this.store.pipe(select(selectMovieActors(movieId: {action.movieId})))
            )
        ),
        filter(([{payload}, actors]) => !!actors
        distinct(payload => payload.movieId)
        mergeMap((payload) => ...
    

    【讨论】:

    • 感谢您的回答!但是有一个问题,如果我使用 distinct 运算符,是否需要进一步使用 withLatestFrom ?
    • 我想你会的,那是让你检查电影是否已经被商店缓存。
    • 如果我的回答能帮助你解决问题,你能接受吗?
    • 我做了一些测试,它似乎工作。有一种情况我不知道如何解决。如果我进入 id 为 1 的电影的演员页面,则会正确发出请求并显示数据。但是,如果我注销并再次登录并转到同一页面,则不再显示任何数据,并且由于“不同”而不会发出任何请求。你知道如何解决这个问题吗?
    • 嗯.. 这是一个艰难的。我会尝试更新答案
    猜你喜欢
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 2020-07-31
    • 1970-01-01
    • 2017-08-28
    • 2018-03-31
    相关资源
    最近更新 更多