简体   繁体   English

如何在不使用store.dispatch的情况下链接异步操作并等待结果

[英]How to chain async actions and wait for the result without store.dispatch

I'm trying to write my INITIALIZE action which should chain some async actions together in the following way 我正在尝试编写我的INITIALIZE操作,该操作应以以下方式将一些异步操作链接在一起

  1. Call the initialize action. 调用初始化动作。
  2. Call two async actions simultaneously. 同时调用两个异步操作。
  3. Wait for the completion of above actions. 等待上述操作完成。
  4. Run additional one action. 运行其他一项操作。
  5. Finish initialization. 完成初始化。

here is the redux flow that I expect 这是我期望的redux流

INITIALIZATION_STARTED => ASYNC_ACTION_A_STARTED AND ASYNC_ACTION_B_STARTED => ASYNC_ACTION_A_FINISHED AND ASYNC_ACTION_B_FINISHED => ASYNC_ACTION_C_STARTED => ASYNC_ACTION_C_FINISHED => INITIALIZATION_FINISHED INITIALIZATION_STARTED => ASYNC_ACTION_A_STARTEDASYNC_ACTION_B_STARTED => ASYNC_ACTION_A_FINISHEDASYNC_ACTION_B_FINISHED => ASYNC_ACTION_C_STARTED => ASYNC_ACTION_C_FINISHED => INITIALIZATION_FINISHED

I managed to achieve that flow using store.dispatch inside my epic, I know that this is anti-pattern and it will be removed in the 1.0.0 version so I would like to know how I can do it using pure epics 我设法在我的史诗中使用store.dispatch来实现该流程,我知道这是反模式,它将在1.0.0版本中删除,所以我想知道如何使用纯史诗来实现

My working solution 我的工作解决方案

export const initEpic = (action$: ActionsObservable<Action>, store) =>
  action$.filter(actions.initialization.started.match)
    .switchMap(action => (
      Observable.forkJoin(
        waitForActions(action$, actions.asyncA.done, actions.asyncB.done),
        Observable.of(
          store.dispatch(actions.asyncA.started(action.payload)),
          store.dispatch(actions.asyncB.started(action.payload)),
        )
      ).map(() => actions.asyncC.started(action.payload))
    )
  );

const waitForActions = (action$, ...reduxActions) => {
  const actionTypes = reduxActions.map(x => x.type);
  const obs = actionTypes.map(type => action$.ofType(type).take(1));
  return Observable.forkJoin(obs);
}

I have also been trying to use forkEpic from this comment like that 我也一直试图从这样的评论中使用forkEpic

export const initEpic = (action$: ActionsObservable<Action>, store) =>
  action$.filter(actions.initialization.started.match)).mergeMap(action =>
    forkEpic(loadTagsEpic, store, actions.asyncA.started(action.payload))
      .concat(
        forkEpic(loadBranchesEpic, store, actions.asyncB.started(action.payload))
      )
      .map(() => actions.asyncC.started(action.payload))
  );

but it doesn't dispatch starting actions ASYNC_ACTION_A_STARTED and _ASYNC_ACTION_B_STARTED 但不会调度启动动作ASYNC_ACTION_A_STARTED_ASYNC_ACTION_B_STARTED

Sounds like merge is perfect for this. 听起来merge非常适合此操作。 You'll start listening for asyncA.done and asyncB.done and then while waiting you'll kick off the requests by emitting asyncA.started and asyncB.started . 您将开始侦听asyncA.doneasyncB.done ,然后在等待期间通过发出asyncA.startedasyncB.started启动请求。 These two streams are merged together as one, so it happens in the correct order and the actions emitted by either are emitted by our epic without needing store.dispatch . 这两个流合并为一个,因此它以正确的顺序发生,并且其中任何一个发出的动作都由我们的史诗发出,而无需store.dispatch

const initEpic = action$ =>
  action$.filter(actions.initialization.started.match)
    .switchMap(action => (
      Observable.merge(
        waitForActions(action$, actions.asyncA.done, actions.asyncB.done)
          .map(() => actions.asyncC.started(action.payload)),
        Observable.of(
          actions.asyncA.started(action.payload),
          actions.asyncB.started(action.payload),
        )
      )
    )
  );

Here is a JSBin demoing: https://jsbin.com/yonohop/edit?js,console 这是一个JSBin演示: https ://jsbin.com/yonohop/edit ? js,console

It doesn't do any of the ASYNC_ACTION_C_FINISHED and INITIALIZATION_FINISHED stuff because code for that was not included in the question so not sure what it would have done. 它不执行任何ASYNC_ACTION_C_FINISHEDINITIALIZATION_FINISHED事情,因为该问题中未包含该代码,因此不确定该怎么做。 😁 😁

You might notice this is mostly a regular RxJS question where the items streaming happen to be actions. 您可能会注意到,这主要是一个常规的RxJS问题,其中的流项目恰好是动作。 This is really helpful because when you ask for help you can ask from the entire RxJS community if you craft the question as generic RxJS. 这真的很有帮助,因为当您寻求帮助时,您可以向整个RxJS社区询问是否将问题设计为通用RxJS。


Note that I listened for done before starting; 请注意,在开始之前我已经听完了。 this is generally a best practice in case done is emitted synchronously after started . 这通常是最佳做法,以防在started后同步发出done If you didn't listen first, you'd miss it. 如果您不先听,那就会错过的。 Since it's async it doesn't matter, but still generally a best practice and helpful when you unit test. 由于它是异步的,所以没有关系,但是通常还是最佳做法,并且在进行单元测试时会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 尝试测试异步操作时,`TypeError: store.dispatch(...).then is not a function` - `TypeError: store.dispatch(…).then is not a function` when trying to test async actions store.dispatch不是函数 - store.dispatch is not a function 我们如何从 Redux - saga 中的 store.dispatch 返回 Promise - saga,以便我们可以等待解析然后在 SSR 中渲染? - How do we return a Promise from a store.dispatch in Redux - saga so that we can wait for the resolve and then render in SSR? Redux store.dispatch 目的 - Redux store.dispatch purpose Store.Dispatch() 重置 Redux Store - Store.Dispatch() Resetting Redux Store 使用Redux的store.getState()和store.dispatch()进行更改而无需订阅React? - Using Redux's store.getState() and store.dispatch() to make changes without subscribing in React? mapDispatchToProps与store.dispatch() - mapDispatchToProps vs. store.dispatch() Redux 中的 store.dispatch 是同步还是异步 - Is store.dispatch in Redux synchronous or asynchronous 我怎样才能在vue.js 2上得到这个。$ store.dispatch的响应? - How can I get response of this.$store.dispatch on the vue.js 2? 如何从 HTML UI 发送自适应卡(使用 store.dispatch):microsoft/BotFramework-WebChat - how to send Adaptive Card from HTML UI (using store.dispatch): microsoft/BotFramework-WebChat
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM