NgRx Effect调用Web服务遇类型错误,修改方案是否可行?
你的修改方向是正确的,但原服务代码里还有一个关键的异步时序问题需要修正,咱们来一步步梳理:
1. 为什么原代码会报错?
NgRx Effect的核心是处理Observable异步流,mergeMap操作符要求传入的函数返回一个Observable类型的值。但你最初的getDirections直接返回了普通对象groupByDirection:
// 原错误服务代码:直接返回普通对象 return groupByDirection as ISchedules;
这导致mergeMap处理的是一个同步值,最终生成的Observable发出的内容不符合Action类型要求(缺少type属性),所以触发了类型错误。
2. 你的修改为什么能解决类型问题?
改成返回of(groupByDirection)后,你把普通对象包装成了一个Observable流:
return of(groupByDirection);
这样mergeMap就能正确处理这个Observable,后续的map操作也能生成符合要求的Action对象,类型错误自然消失——这一步的修改是完全正确的。
3. 隐藏的异步问题:原服务没有等待HTTP请求完成
不过你当前修改后的服务代码还有一个致命问题:data.map里的this.http.get是异步操作,但你没有等待这些请求完成就返回了groupByDirection,这会导致返回的对象是空的或者不完整(因为HTTP请求还没结束)。
优化后的正确服务代码
应该用forkJoin来并行处理所有HTTP请求,等待全部完成后再组装结果:
import { forkJoin, Observable } from 'rxjs'; import { map, reduce } from 'rxjs/operators'; getDirections(data: string[], date:string): Observable<ISchedules> { // 为每个方向创建HTTP请求Observable const directionRequests = data.map(elm => { const dirUrl = `.....date=${date}&directions=${elm}`; return this.http.get<ISchedules>(dirUrl).pipe( map(dirData => ({ [elm]: dirData.data })) // 保留方向与数据的对应关系 ); }); // 等待所有请求完成后,合并结果为一个ISchedules对象 return forkJoin(directionRequests).pipe( map(results => { return results.reduce((acc, current) => ({ ...acc, ...current }), {} as ISchedules); }) ); }
4. Effect代码的小优化(类型安全)
去掉ofType<any>,直接用Action类本身,同时用实例化Action的方式替代手动写对象,提升类型安全性:
$LoadSchedulingsByMission = createEffect(() => this.actions$.pipe( ofType(ESchedulesActions.GetSchedulesByDirection), // 移除<any>,利用类型推断 mergeMap(action => this.apiCallsService.getDirections(action.payload, '2016-04-18').pipe( map(trips => new GetDirectionsSuccess(trips)), // 直接实例化Success Action catchError(() => EMPTY) )) ));
总结:你的初始修改解决了类型错误,但结合forkJoin的优化才能真正保证数据的完整性,这才是完整的正确方案。
内容的提问来源于stack exchange,提问作者infodev
相关产品推荐
相关产品推荐

