您如何将史诗转换为异步功能?

时间:2019-05-07 13:03:22

标签: rxjs redux-observable

以下代码可以正常运行:

export const myEpic = (action$: any) => action$.pipe(
   ofType("TEST"),
   mergeMap(() => concat(
      // fires an actionCreator and triggers another epic
      of(actionOne()),
      // fires an actionCreator
      of(actionTwo())
   ))
);

问题是我需要从actionOne中获得数据,然后才能actionTwo被解雇,而且似乎没有发生。所以我想使它像一个异步函数:

export const myEpic = (action$: any) => action$.pipe(
   ofType("TEST"),
   mergeMap(async () => concat(
      of(await actionOne()),
      of(actionTwo())
   ))
);

这会引发错误:

Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

编辑

其他相关代码:

// main component that loads
constructor(props) {
   props.dispatch(init());
}
componentDidUpdate(prevProps) {
   if (prevProps.actionTwoFlag !== this.props.actionTwoFlag) {
      // do stuff with result from actionOne
      // error is thrown here because there's no data
   }
}

// actions
export const init = () => ({ type: "TEST" });
export const actionOne = () => ({ type: "ACTION_ONE" });
export const actionOneDone = (result) => ({ type: "ACTION_ONE_DONE", payload: result });
export const actionTwo = () => ({ type: "ACTION_TWO", payload: true });

// epics
export const actionOneEpic = (action$: any) => action$.pipe(
   ofType("ACTION_ONE"),
   mergeMap(() =>
      ajax(..).pipe(
         mergeMap(result => concat(
            of(actionOneDone(result)),
            ...
         ))
      )
   )
);
);

1 个答案:

答案 0 :(得分:0)

有多种解决方法。

1-一种方法是仅在actionTwo上使用 defer()运算符。 defer()运算符将执行的操作是在订阅时执行代码,由于它们是串联的,因此对of(actionTwo())的订阅将在of(actionOne())完成之后进行: / p>

export const myEpic = (action$: any) => action$.pipe(
   ofType("TEST"),
   mergeMap(() => concat(
      of(actionOne()),
      defer(() => of(actionTwo()))
   ))
);

2- 另一个选项只是执行 switchMap(),这也将确保在创建可观察的of(actionTwo())时,of(actionOne ())的观察值已经发出并完成。 switchMap()还确保顺序顺序,因此您可以安全地删除concat()运算符:

    export const myEpic = (action$: any) => action$.pipe(
       ofType("TEST"),
       mergeMap(() => 
          of(actionOne()).pipe(switchMap(() => of(actionTwo())))
       )
    );

编辑

现在,我想我明白了,尽管我对redux可观察的史诗还不太熟悉。我在这里看到了一个解决方案:Composing and sequencing multiple epics in redux-observable 可能会解决您的第二个问题。在此基础上,我将提出两个建议。

第一个提案:

该提议只是构建了一个史诗般的内容,该史诗首先将动作一推入,然后等待动作一完成以将动作二推入。

export const myEpic = (action$: any) => action$.pipe(
    ofType('TEST'),
    map(() => actionOne()),
    mergeMap(() => {
        return action$.pipe(
            ofType('ACTION_ONE_DONE'),
            take(1),
            map(() => actionTwo()),
        );
    })
);

第二个提案:

一史无前例。由于动作一和动作二是相关的(一个彼此依赖),将两者合并为一个史诗可能是有意义的,就像这样:

export const myEpic = (action$: any) => action$.pipe(
    ofType('TEST'),
    map(() => actionOne()),
    mergeMap(() => {
        return ajax(..).pipe(
            mergeMap((data) => {
                return concat(
                    actionOneDone(action),
                    of(actionTwo()).mergeMap(() => /* Do action two */ actionTwoDone())
                )
            }),
        )
    })
);

希望这会有所帮助!