You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:01:01