【问题标题】:How to make sure one epic is completed before executing the next epic?如何确保在执行下一个史诗之前完成一个史诗?
【发布时间】:2020-06-25 21:46:36
【问题描述】:

这是我们升级到版本1.x 后在我们的应用程序中遇到的问题,他们在其中引入了队列操作调度史诗,以在当前堆栈完成后执行 (https://github.com/redux-observable/redux-observable/pull/493)。

想象一个动作(INIT_STUFF),它有一个返回动作列表的史诗(INIT_AINIT_B,按此顺序)。这些行动中的每一个都有自己的史诗。他们在那里做一些事情并返回一个修改商店的动作。

在以前的 redux-observable 版本中,INIT_B 的史诗可以依赖于 INIT_A 的史诗已经完成执行并对存储进行更改的事实。然后这个史诗就可以使用更新后的商店。

在最新版本中,INIT_AINIT_B 的史诗都按各自的顺序执行,但它们返回的操作(修改存储)被推迟到最后一个史诗完成。这意味着INIT_B 的史诗无法访问由INIT_A 制作的商店中的更新。

这是我正在谈论的内容的简单实现:https://redux-observable-playground-ip3qfb.stackblitz.io

这样的用例的迁移路径是什么?

【问题讨论】:

  • 感谢堆栈闪电战!它尝试记录 store$.initialized 但是据我所知initialized 绝不是您的 redux 状态中的属性。从演示中也不清楚预期的行为是什么?我没有看到任何两个史诗相互依赖。另外,我认为您的描述对我来说很有意义,但我想了解 stackblitz 演示以确认。
  • 糟糕,我想我现在得到了演示。 initialized 是一个对象,因为它是提供给 combineReducers 的一个 reducer 的名称。
  • @jayphelps 我更新了它以更好地反映我的意思。

标签: redux-observable


【解决方案1】:

这个确实很棘手。就个人而言,我认为有两个史诗需要依赖这样的东西是一种反模式,特别是因为它们都是同步的。我认为这不仅仅是因为它是人为的,否则我认为你不会面临这个问题。

如果 Epic B 真的应该等到 Epic A 准备好后才开始,则要么父级 (initializeStuffEpic) 应确保执行此序列,要么 Epic B 可以侦听一些信号以知道 A 已准备好,因为 Epic“不应该” to" 像这样泄露他们的实现细节。或者,这可能表明逻辑不应该是两个独立的 Epic,而应该只是一个,使用函数组合来保持事物的组织性。

Epic 通常响应动作作为它们的信号,尽管第二个参数 state$ 也是一个 Observable 并且也可以被订阅。如果你真的更喜欢这样做,我认为这可能是最简单的方法:

https://stackblitz.com/edit/redux-observable-playground-g1nuis?file=initialize.js

export const initBEpic = (action$, state$) =>
  action$.pipe(
    ofType("INITIALIZE_B"),
    mergeMap(({ payload }) => {
      return state$.pipe(
        filter(state => state.initialized.A), // Wait until it is indeed true
        take(1), // Very important!
        map(() => ({
          type: "IS_B_READY",
          payload: true
        }))
      );
    })
  );

与大多数事情一样,也有一些注意事项。如果 A 从未准备好怎么办?

--

redux-observable v1.0 中对操作调度方式所做的更改旨在使某些事情更直观,同时阻止其他一些不良模式。在该决定期间未考虑此特定模式,因此我不完全确定是否会更改行为以使您的用例更容易。虽然不幸的是,有些看似明显的东西不起作用,但它可能是一个可以接受的权衡,因为这是我第一次看到这种情况。

将 Epics 几乎视为单独的进程是有帮助的(尽管它们不是。)在没有实际信号(动作或 state$ 更新)的情况下隐式假设共享状态的时间是不安全的。

我们总是有机会为 v2 更改它,但是需要有人为特定更改提出建议或 PR,而调度的工作原理(QueueScheduler 的内部实例)有点复杂。

【讨论】:

  • 我使用combineLatest 将史诗B 与史诗A 返回的最终动作联系起来怎么样?这将确保史诗仅在先决操作已调度时才会执行。我不确定combineLatest 是否是正确的可观察对象。
  • 我最终使用了combineLatestfirst
  • 亲爱的 jayphhelps,我为类似的问题提出了相同的解决方案,并且对此感到非常兴奋;您能否详细说明为什么这是一种反模式?如果您可以将我指向该主题的任何资源,那就太好了(在我的情况下,我将它用于等待状态处于特定条件的史诗,这可能是立即的或在一些 http 请求之后;返回状态流似乎比等待分派的动作更强大?)
  • @jayphelps 关于永远等待的问题,这可以很容易地通过这个 stackblitz stackblitz.com/edit/… 中的超时来解决
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 2019-09-06
  • 1970-01-01
  • 1970-01-01
  • 2021-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多