如何延迟一个史诗直到另一个发出值 [英] How to delay one epic until another has emitted a value

查看:51
本文介绍了如何延迟一个史诗直到另一个发出值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 redux-observable 中,我需要在执行 API 请求之前等待,直到另一个史诗完成.使用 combineLatest 不起作用,APP_INITIALIZED 完成后没有任何反应.我也试过 withLatestFrom 但都没有效果.

In redux-observable I need to wait before doing an API request until another epic has completed. Using combineLatest doesn't work, nothing happens after APP_INITIALIZED finishes. I also tried withLatestFrom but neither works.

const apiGetRequestEpic = (action$, store) => {
  return Observable.combineLatest(
    action$.ofType('APP_INITIALIZED'),
    action$.ofType('API_GET_REQUEST')
      .mergeMap((action) => {
        let url = store.getState().apiDomain + action.payload;
        return ajax(get(url))
          .map(xhr => {
            return {type: types.API_RESPONSE, payload: xhr.response};
          })
          .catch(error => {
            return Observable.of({ type: 'API_ERROR', payload: error });
          });
      })
  );
};

结合最新定义

推荐答案

一种方法是(使用假名),当接收到初始动作 API_GET_REQUEST 时,你立即开始监听单个 INITIALIZE_FULFILLED,它表示初始化(或其他)已经完成——我们实际上将在稍后开始.收到后,我们将mergeMap(或switchMap 以您的用例为准)放入我们的调用中,以发出其他ajax 请求并执行通常的业务.最后,开始我们正在等待的实际初始化的技巧是在整个链的末尾添加一个 startWith() —— 这将发出和分派另一个史诗正在等待的动作.

One approach is (using pseudo names), when receiving the initial action API_GET_REQUEST you immediately start listening for a single INITIALIZE_FULFILLED, which signals that the the initialization (or whatever) has completed--we'll actually kick it off in a bit. When received, we mergeMap (or switchMap whichever for your use case) that into our call to make the other ajax request and do the usual business. Finally, the trick to kick off the actual initialization we're waiting for is adding a startWith() at the end of that entire chain--which will emit and dispatch the action the other epic is waiting for.

const initializeEpic = action$ =>
  action$.ofType('INITIALIZE')
    .switchMap(() =>
      someHowInitialize()
        .map(() => ({
          type: 'INITIALIZE_FULFILLED'
        }))
    );

const getRequestEpic = (action$, store) =>
  action$.ofType('API_GET_REQUEST')
    .switchMap(() =>
      action$.ofType('INITIALIZE_FULFILLED')
        .take(1) // don't listen forever! IMPORTANT!
        .switchMap(() => {
          let url = store.getState().apiDomain + action.payload;
          return ajax(get(url))
            .map(xhr => ({
              type: types.API_RESPONSE,
              payload: xhr.response
            }))
            .catch(error => Observable.of({
              type: 'API_ERROR',
              payload: error
            })); 
        })
        .startWith({
          type: 'INITIALIZE'
        })
    );

您没有提到一切是如何工作的,所以这只是您需要针对您的用例修改的伪代码.

You didn't mention how everything works, so this is just pseudo code that you'll need to amend for your use case.

综上所述,如果您除了在这个位置之外从未调用过初始化,您也可以直接将该代码包含在单个史诗本身中,或者只是创建一个辅助函数来抽象它.将它们作为单独的史诗通常意味着您的 UI 代码可以独立触发它们中的任何一个——但为了测试目的将它们分开可能仍然是好的.只有您可以拨打该电话.

All that said, if you don't ever call that initialization except in this location, you could also just include that code directly in the single epic itself, or just make a helper function that abstracts it. Keeping them as separate epics usually means your UI code can independently trigger either of them--but it might still be good to separate them for testing purposes. Only you can make that call.

const getRequestEpic = (action$, store) =>
  action$.ofType('API_GET_REQUEST')
    .switchMap(() =>
      someHowInitialize()
        .mergeMap(() => {
          let url = store.getState().apiDomain + action.payload;
          return ajax(get(url))
            .map(xhr => ({
              type: types.API_RESPONSE,
              payload: xhr.response
            }))
            .catch(error => Observable.of({
              type: 'API_ERROR',
              payload: error
            }));
        })
        .startWith({ // dunno if you still need this in your reducers?
          type: 'INITIALIZE_FULFILLED'
        })
    );

这篇关于如何延迟一个史诗直到另一个发出值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆