【问题标题】:Invoking epics from within other epics从其他史诗中调用史诗
【发布时间】:2017-02-16 14:14:34
【问题描述】:

首先是这个很棒的图书馆的许多道具!不过,我仍在为一个用例而苦苦挣扎。我想先调用另一个史诗并等到它完成后再继续当前的史诗。假设我有一个用户可以更改内容的表单。在将其他数据加载到表单之前,我想先保存当前的更改。对此有什么想法吗?

【问题讨论】:

    标签: reactjs redux rxjs redux-observable


    【解决方案1】:

    听起来如你所愿:如果一部史诗想要开始另一部史诗的作品并且 等待它完成后再继续。

    一种方法是(使用伪名称),当接收到初始操作 LOAD_OTHER_DATA 时,您立即开始侦听单个 SAVE_FORM_FULFILLED,这表明表单已保存(我们稍后会启动它) .收到后,我们将mergeMap(或switchMap,在这种情况下无关紧要)加入我们的调用以加载其他数据loadOtherDataSomehow() 并执行常规业务。最后,开始实际保存我们正在等待的表单的技巧是在整个链的末尾添加一个startWith() - 这将发出并调度操作以实际保存表单。

    const saveFormEpic = (action$, store) =>
      action$
        .ofType('SAVE_FORM')
        .switchMap(() =>
          saveFormSomeHow(store.getState().formDataSomewhere)
            .map(details => ({
              type: 'SAVE_FORM_FULFILLED'
            }))
        );
    
    const loadOtherDataEpic = action$ =>
      action$
        .ofType('LOAD_OTHER_DATA')
        .switchMap(() =>
          action$.ofType('SAVE_FORM_FULFILLED')
            .take(1) // don't listen forever! IMPORTANT!
            .mergeMap(() =>
              loadOtherDataSomeHow()
                .map(otherData => ({
                  type: 'LOAD_OTHER_DATA_FULFILLED',
                  payload: otherData
                }))
            )
            .startWith({
              type: 'SAVE_FORM'
            })
        );
    

    你没有提到你的加载和保存是如何工作的,所以这只是你需要为你的用例修改的伪代码。

    【讨论】:

    • 哇,感谢您的详尽回答!除此之外,我还能再问一个小问题吗?保存是可选的,如“当用户没有自己保存时,我希望史诗为他做这件事”。所以我查看了 Observer.if() 方法,看起来很合适,但我不知道可以在“loadOtherDataEpc”中选择性地执行它。
    • 只使用一个简单的 if/else 条件
    • 正是我想要的!再次感谢您的详尽回答!
    • @robinvdvleuten 不客气!如果有机会,请接受这个答案:)
    【解决方案2】:

    @jayphelps,我只想对您回答的所有问题表示感谢,他们确实帮助我解决了许多问题。

    我正在尝试制定我的问题,发现您已经在这里回答了它并设法使用您的示例解决了我的问题。

    我的示例有/有 2 个我想要/ed 互相调用的 expics:

    const requestNameEpic = action$ =>
      action$.ofType("REQUEST_NAME")
        .switchMap(({id}) =>
          Observable.of(`name returned by 'ajax' call, using id: ${id}`) // Ajax simulation
            .delay(1000)
            .map(name => ({type: "LOAD_NAME", name}))
        );
    
    const requestAgeEpic = action$ =>
      action$.ofType("REQUEST_AGE")
        .switchMap(({name}) =>
          Observable.of(`age returned by 'ajax' call, using name: [${name}]`)
            .delay(1000)
            .map(age => ({type: "LOAD_AGE", age}))
        );
    

    我设法解决它的方法是:

    const requestDetailsEpic = action$ =>
      action$.ofType("LOAD_NAME")
        .map(({name}) => ({type: "REQUEST_AGE", name}));
    

    所以调度 REQUEST_NAME 也会调度 REQUEST_AGE,但我永远无法只调度 LOAD_NAME。

    我重构了您的示例以获得:

    const requestDetailsEpic = action$ =>
      action$.ofType("REQUEST_DETAILS")
        .switchMap(({id}) =>
          action$.ofType("LOAD_NAME")
            .take(1) // don't listen forever! IMPORTANT!
            .map(({name}) => ({type: "REQUEST_AGE", name}))
            .startWith({type: "REQUEST_NAME", id})
      );
    

    再次感谢您在 redux-observable 上所做的所有出色工作以及所有社区的支持。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多