React/Redux中Observable.merge在Redux Observable Epic中表现差异的原因咨询
兄弟,这问题本质是RxJS里冷流的执行时机和流组合位置的问题,我给你掰扯清楚:
为什么epic1达不到你的预期?
先看你写的第一个epic:
const epic1 = action$ => action$ .ofType("A") .mapTo({ type: "B" }) .merge(Observable.of({ type: "C" }));
这里的merge是把两个流直接拼在了一起,但这两个流的触发逻辑完全不一样:
- 第一个流:
action$.ofType("A").mapTo({type: "B"}),只有当收到"A"动作时才会发射"B",属于“按需触发”的流。 - 第二个流:
Observable.of({type: "C"})是个冷Observable,它的特性是:一旦被订阅(这里就是epic启动的时候),就会立刻把值发射出去,之后就再也不会有动静了。
所以实际运行效果是:应用刚启动时会自动发一次"C",之后每次触发"A"动作,只会输出"B",完全做不到“每次触发"A"就同时输出"B"和"C"”的需求。
为什么epic2能满足需求?
再看第二个epic的写法:
const epic2 = action$ => action$ .ofType("D") .mergeMap(value => Observable.merge( Observable.of({ type: "E" }), Observable.of({ type: "F" }) ));
这里的核心变化是把merge放到了mergeMap的回调函数里面:
- 每次收到"D"动作时,
mergeMap都会执行一次回调,重新创建一个新的合并流——这个新流里的两个Observable.of都会被重新订阅,自然就会各自发射"E"和"F"。 - 简单说就是:每触发一次"D",就会重新生成一次"E"和"F"的发射逻辑,完美实现“每次触发动作就输出两个不同Action”的需求。
额外给你个更简洁的写法
其实RxJS支持直接返回数组(会自动转成Observable),你可以把代码简化成这样:
const epic3 = action$ => action$ .ofType("D") .mergeMap(() => [ { type: "E" }, { type: "F" } ]);
效果和epic2完全一样,代码更清爽~
内容的提问来源于stack exchange,提问作者Laurent De Cant
相关产品推荐
相关产品推荐

