使用redux-observable 1.0.0-alpha.2时forkEpic丢失getRailways.request动作问题
你遇到的问题核心在于:forkEpic 内部仅将 getRailways.request() 作为局部动作传给了 getRailwaysEpic,但并没有把这个动作分发到全局的 Redux action 流中。所以 Redux Store 根本没有接收到 getRailways.request 动作,自然在流程里看不到它;而 getRailways.success/failure 是由 getRailwaysEpic 直接返回的,所以会直接跳转到这一步。
为什么会这样?
看你的 forkEpic 实现:
function forkEpic<T extends Action, S>( epicFactory: Epic<T, S>, state$: StateObservable<S>, ...actions: T[] ) { const actions$ = ActionsObservable.of(...actions); return epicFactory(actions$, state$, null); }
这里的 actions$ 是一个局部的 Observable,只供传入的 epicFactory(也就是 getRailwaysEpic)内部使用,这些动作并没有被 dispatch 到全局 Store,所以 DevTools 或你的全局 action 监听都捕获不到 getRailways.request。而 getRailwaysEpic 只是处理了这个局部动作,直接返回了 success/failure,导致流程跳过了 request 步骤。
解决方案
这里有两种常用的修复方式,你可以根据需求选择:
方案一:直接在 initEpic 中分发 getRailways.request 动作
既然你的 getRailwaysEpic 本来就是监听全局的 getRailways.request 动作,那完全不需要用 forkEpic,直接在 initEpic 中发出这个动作即可:
const initEpic: Epic<FiltersActions, AppState> = (action$, state$) => action$.pipe( filter(isActionOf(init)), switchMap(({ payload: { date, depotId, locTypeId, railwayId } }) => concat( of(selectDate(date)), of(getRailways.request()) // 直接发出request动作,全局action$会捕获到并触发getRailwaysEpic )) );
这样流程就会变成:init → selectDate → getRailways.request → getRailways.success/failure,完全符合你的预期。
方案二:修改 forkEpic,让它同时发出传入的动作和 Epic 输出
如果你坚持要使用 forkEpic 这种封装方式,可以修改它,让它先把传入的动作 emit 到全局流中,再返回 Epic 的输出:
function forkEpic<T extends Action, S>( epicFactory: Epic<T, S>, state$: StateObservable<S>, ...actions: T[] ) { const actions$ = ActionsObservable.of(...actions); const epicOutput$ = epicFactory(actions$, state$, null); // 先发出传入的动作(这样全局Store能收到),再发出Epic处理后的结果 return concat(of(...actions), epicOutput$); }
这样调用 forkEpic(getRailwaysEpic, state$, getRailways.request()) 时,会先分发 getRailways.request 动作,再返回 success/failure,流程就完整了。
额外提示
其实 redux-observable 的设计理念是通过监听全局 action 流来触发副作用,所以方案一更符合它的惯用模式,也更简洁易懂。除非你有特殊的封装需求,否则优先选择方案一。
内容的提问来源于stack exchange,提问作者abdurahmanus

