【发布时间】: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.movieId}) 动作。
【问题讨论】: