【问题标题】:Catching Errors while calling an API from a NgRx effect从 NgRx 效果调用 API 时捕获错误
【发布时间】:2020-02-29 00:11:43
【问题描述】:

我正在尝试捕获有关特定操作效果的错误。一切正常,无论通话成功还是失败。但是,我认为代码非常冗长,可以改进,特别是:

  • catchError 部分,我返回empty(),但我认为应该返回SavedReplyDeleteFailed 操作。这样做时,整个效果会中断并且无法编译,不确定处理此问题的最佳做法是什么。
  • 我过于依赖tapdispatch 而不是从map/mergeMap 回调中返回操作。当我这样做时,效果编译也会中断。

如何应用上述改进?

    deleteSavedReply = createEffect(() => this.actions$.pipe(
        ofType(SavedRepliesActions.SavedReplyDeleteRequested),
        mergeMap( action => {
            this.store.dispatch( SavedRepliesActions.DeleteLoading({ isLoading: true }) );
            return this.savedRepliesService.deleteSavedReply(action.id).pipe(
                tap(res => {
                    this.store.dispatch( SavedRepliesActions.SavedReplyDeleteSucess({ id: action.id }));
                    this.toastr.success( 'Saved Reply has been successfully deleted');
                }),
                catchError((error) => {
                    this.store.dispatch( SavedRepliesActions.SavedReplyDeleteFailed({message: error.message}) );
                    this.toastr.error( error.message, 'Something went wrong');
                    this.store.dispatch( SavedRepliesActions.DeleteLoading({ isLoading: false }) );
                    return empty();
                })
            );
        }),
        map(() => {
            return SavedRepliesActions.DeleteLoading({ isLoading: false });
        }),
    ));

【问题讨论】:

    标签: angular ngrx


    【解决方案1】:

    你可以选择一种更被动的方式(使用强大的 RxJS),这样可以稍微简化你的代码:

    deleteSavedReply$ = createEffect(() => this.actions$.pipe(
      ofType(SavedRepliesActions.SavedReplyDeleteRequested),
      mergeMap(action => this.savedRepliesService.deleteSavedReply(action.id).pipe(
        switchMap(res => [
          SavedRepliesActions.SavedReplyDeleteSucess({ id: res.id }),
          UiActions.showToastrSuccess('Saved Reply has been successfully deleted')
        ]),
        catchError(error => of(
          SavedRepliesActions.SavedReplyDeleteFailed({ message: error.message }),
          UiActions.showToastrError(error.message, 'Something went wrong')
        ]))
      ))
    ))
    

    要做到这一点,以redux 的心态,你应该:

    • 创建 2 个新动作 UiActions.showToastrSuccessUiActions.showToastrError 以显示消息 Toastr。显示消息是操作的可能目标。

    • reducer 用于您的loading 标志。它是你状态的一部分,所以应该在 reducer 中改变它的值来代替效果。

    例如:

    on(SavedRepliesActions.SavedReplyDeleteFailed, (state) => ({
      ...state,
      loading: false
    })),
    
    on(SavedRepliesActions.SavedReplyDeleteRequested, (state) => ({
      ...state,
      loading: true
    })),
    

    其他选项

    请注意,另一种选择(或改进...)可能是在 SavedReplyDeleteSucess 操作中调度 Toastr 操作。 例如:

    deleteSavedReply$ = createEffect(() => this.actions$.pipe(
      ofType(SavedRepliesActions.SavedReplyDeleteRequested),
      mergeMap(action => this.savedRepliesService.deleteSavedReply(action.id).pipe(
        map(res => SavedRepliesActions.SavedReplyDeleteSucess({ id: res.id }))
        catchError(error => of(SavedRepliesActions.SavedReplyDeleteFailed({ message: error.message })))
      ))
    ))
    
    savedReplyDeleteSucess$ = createEffect(() => this.actions$.pipe(
      ofType(SavedRepliesActions.SavedReplyDeleteSucess),
      map(_ => UiActions.showToastrSuccess('Saved Reply has been successfully deleted'))
    ))
    
    savedReplyDeleteFailed$ = createEffect(() => this.actions$.pipe(
      ofType(SavedRepliesActions.SavedReplyDeleteFailed),
      map(message => UiActions.showToastrError(error.message, 'Something went wrong'))
    ))
    

    这里的优点是您可以通过在成功或失败的情况下添加一些额外的效果来使您的代码不断发展。 例如:

    savedReplyDeleteFailed$ = createEffect(() => this.actions$.pipe(
      ofType(SavedRepliesActions.SavedReplyDeleteFailed),
      switchMap(message => [
        UiActions.showToastrError(error.message, 'Something went wrong')),
        SystemActions.sendTraceError(error)
    ))
    

    希望它会有所帮助。

    【讨论】:

    • 好东西,对于 UiActions.showToastSuccess,这是另一个具有自身效果的操作,它实际上会触发 Toastr 服务,对吗?
    • 绝对是的。它可以是一个单独的商店,其中包含与您的应用程序全局共享的减速器和效果,您可以在其中管理您的 UI。但这只是一个例子。
    猜你喜欢
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多