NgRx Effect获取无人机列表后批量分发Action问题排查
解决NgRx Effect批量分发多个Action的问题
咱们一步步拆解你的问题,先搞清楚为什么之前的写法都不对,再给出正确的实现方式:
为什么最初的代码报错?
你的第一个版本里,map函数内部既没有return任何Action,也没有把创建的Action传递出去——forEach里只是创建了Action实例,但没有让Effect把它们分发。最后整个map函数返回undefined,NgRx自然会报错说“分发了无效的action”。
为什么修改后的代码只触发了成功Action?
第二个版本里,你虽然return了GetUsedDronesSuccess,但forEach里创建的OpenUsedDroneUpdateChannelRequest依然只是被创建,没有被Effect分发出去——forEach不会收集或返回这些Action,所以只有最后return的那个成功Action被处理了。
正确的实现方式:用mergeMap+of分发多个Action
要批量分发多个Action,你需要把所有要分发的Action转换成一个可观察对象,然后用mergeMap(这里用mergeMap更合适,因为我们要处理所有Action)来展平这个可观察对象,让Effect逐个分发里面的Action。
调整后的代码如下:
@Effect() getUsedDrones$ = this.actions$.pipe( ofType<featureActions.GetUsedDronesRequest>(featureActions.ActionTypes.GetUsedDronesRequest), switchMap((action) => this.droneDataService.getUsedDrones(action.payload).pipe( // 把map改成mergeMap,用来处理多个Action的可观察对象 mergeMap(drones => { // 先为每个无人机创建通道请求Action const channelActions = drones.map(drone => new featureActions.OpenUsedDroneUpdateChannelRequest({ droneId: drone.id, projectId: environment.projectId }) ); // 加上成功Action const allActions = [ ...channelActions, new featureActions.GetUsedDronesSuccess({ drones }) ]; // 用of把Action数组转换成可观察对象,每个Action会被依次分发 return of(...allActions); }), catchError((error: HttpErrorResponse) => { this.snackBar.open(this.translate.instant('ERRORS.HTTP.GENERIC'), this.translate.instant('BUTTONS.OK'), {duration: 2500}); return of(new featureActions.GetUsedDronesFailed({error})); }), )), );
关键细节说明:
- 用
map代替forEach来生成通道请求Action数组:forEach只是执行操作,不会返回结果,而map会把每个无人机转换成对应的Action,方便我们收集。 - 用
of(...allActions)把Action数组转换成可观察对象:of会依次发射数组里的每个元素,也就是每个Action。 - 用
mergeMap来处理这个可观察对象:mergeMap会把可观察对象里的每个Action都传递给Effect,让NgRx依次分发它们。
如果你想控制Action的分发顺序(比如先分发所有通道请求,再分发成功Action),上面的写法已经能保证顺序,因为of是同步发射元素的。
内容的提问来源于stack exchange,提问作者Crocsx
相关产品推荐
相关产品推荐

