【问题标题】:Emit multiple actions within catchError - Redux Observable在 catchError 中发出多个操作 - Redux Observable
【发布时间】:2021-10-29 10:30:17
【问题描述】:

我有使用 rxjs 史诗的身份验证功能:

export const authWithEmailPasswordEpic = action$ =>
action$.pipe(
    filter(authUser.match),
    switchMap(({payload}) =>
        defer(() =>
            from(firebaseEmailPasswordAuth(payload)).pipe(
                mergeMap(() => of(clearAlertState(), stopLoading())),
                catchError(err =>
                    of(clearState(), createAlert({
                        status: err.code,
                        alertType: RED_ALERT,
                        alertTitle: err.message
                    })),
                )
            )
        )
    )
);

如果用户凭据不正确,我将发送警报,但我也想在 5 秒左右后删除警报。因此,我相信我需要发出两个动作来实现这一点,第二个是:

of(toggleAlert()).pipe(delay(5000)))

我将如何实现这一目标,或者有更好的方法吗?

【问题讨论】:

    标签: reactjs rxjs rxjs6 redux-observable


    【解决方案1】:

    你在正确的轨道上......对于一个更简单的版本,我会使用concat,我认为它读起来更好:

    export const authWithEmailPasswordEpic = (action$) =>
      action$.pipe(
        filter(authUser.match),
        switchMap(({ payload }) =>
          from(firebaseEmailPasswordAuth(payload)).pipe(
            mergeMap(() => of(clearAlertState(), stopLoading())),
            catchError((err) =>
              concat(
                [
                  clearState(),
                  createAlert({
                    status: err.code,
                    alertType: RED_ALERT,
                    alertTitle: err.message,
                  }),
                ],
                timer(5000).pipe(
                  mapTo(toggleAlert())
                )
              )
            )
          )
        )
      );
    

    有了这个图案,你就可以让它变得更漂亮。想象一下,您想要发送toggleAlert,除非用户发送了Action.CloseAlert。然后你可以把 timer.pipe 换成:

    timer(5000).pipe(
      mapTo(toggleAlert()),
      takeUntil(action$.pipe(
        filter((action) => action.type === Action.CloseAlert)
      ))
    );
    

    另一个注意事项 - 我认为这里不需要defer()。 switchMap 立即订阅函数的结果,所以它应该不重要。需要的话加回来

    【讨论】:

      【解决方案2】:

      您可以在catchError 之后使用delay(5000),然后使用mergeWithof(toggleAlert()) 来实现,如下所示:

      export const authWithEmailPasswordEpic = action$ =>
        action$.pipe(
          filter(authUser.match),
          switchMap(({ payload }) =>
            defer(() =>
              from(firebaseEmailPasswordAuth(payload)).pipe(
                mergeMap(() => of(clearAlertState(), stopLoading())),
                catchError(err =>
                  of(
                    clearState(),
                    createAlert({
                      status: err.code,
                      alertType: RED_ALERT,
                      alertTitle: err.message
                    })
                  )
                ),
                mergeWith(of(toggleAlert()).pipe(delay(5000)))
              )
            )
          )
        );
      

      【讨论】:

      • 我认为这行不通。这会将任何操作(包括clearStatecreateAlert)延迟5000 毫秒,然后在它们发出之前将它们全部替换为toggleAlert
      • 是的,你没事,我的错。谢谢你的评论。顺便说一句,我更新了我的答案。再次感谢。 :)
      猜你喜欢
      • 2017-04-14
      • 2019-02-17
      • 2018-09-15
      • 2018-07-23
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多