@ngrx Effect 没有第二次运行

Posted

技术标签:

【中文标题】@ngrx Effect 没有第二次运行【英文标题】:@ngrx Effect does not run the second time 【发布时间】:2017-10-26 02:17:29 【问题描述】:

我刚刚开始了解@ngrx/store 和@ngrx.effects,并在我的Angular/Ionic 应用程序中创建了我的第一个效果。它第一次运行正常,但如果我再次将事件发送到商店(即再次单击按钮时),什么也没有发生(没有进行网络调用,控制台日志中没有任何内容)。有什么明显的我做错了吗?效果如下:

@Effect() event_response$ = this.action$
    .ofType(SEND_EVENT_RESPONSE_ACTION)
    .map(toPayload)
    .switchMap((payload) => this.myService.eventResponse(payload.eventId,payload.response))
    .map(data => new SentEventResponseAction(data))
    .catch((error) => Observable.of(new ErrorOccurredAction(error)));

谢谢

【问题讨论】:

【参考方案1】:

听起来好像发生了错误。在这种情况下,catch 返回的 observable 中的动作将被发送到效果的流中,然后效果将完成 - 这将阻止效果在错误动作发出后运行。

mapcatch 移动到switchMap

@Effect() event_response$ = this.action$
  .ofType(SEND_EVENT_RESPONSE_ACTION)
  .map(toPayload)
  .switchMap((payload) => this.myService
    .eventResponse(payload.eventId, payload.response)
    .map(data => new SentEventResponseAction(data))
    .catch((error) => Observable.of(new ErrorOccurredAction(error)))
);

switchMap 中组合catch 会在发生错误时阻止效果完成。

【讨论】:

这是否意味着使用 Angular 的全局错误处理程序无法使用效果? ***.com/questions/47896171/… 对于pipeable 运算符和catchError 仍然如此。我花了一段时间才找到这个问题!谢谢。 供参考 - 您可以在不进入回调地狱的情况下执行此操作,只需在管道末尾添加一个 catchError:github.com/ngrx/platform/issues/646#issuecomment-398640097 @亚当尼斯。但是,我建议返回 caught.pipe(startWith(/* error action */)) 而不是通过商店显式调度 - 正如链接的 GitHub 评论中所做的那样 - 我认为这不是我认为应该做的事情。 @cartant - 这又回到了管道的内部。你能做到吗:.pipe(...,catchError((err,caught) => caught),startWith(() => /* error action */)?我发现在效果中做 store.dispatch 也很恶心,我只是觉得它比把管道放在管道里更恶心。【参考方案2】:

您必须将map()catchError() 移动到swithchMap(),如下所示

@Effect()
public event_response$ = this.action$.pipe(
    ofType(SEND_EVENT_RESPONSE_ACTION),
    switchMap((payload) => 
        return this.myService.eventResponse(payload.eventId,payload.response).pipe(
            map((data: DataType) => new SentEventResponseAction(data)),
            catchError((error) => Observable.of(new ErrorOccurredAction(error)))
        )
    );
 );

请注意,myService 中的 evetResponse() 方法应该返回一个 observable 以便之后使用管道。 如果你在服务中的方法返回Promise,你可以通过使用rxjs包中的from将它转换成一个observable,如下所示:

import  from  from 'rxjs';
...
const promise = this.myService.eventResponse(payload.eventId,payload.response);
const observable = from(promise);
return observable.pipe(...

更多详细介绍请看link

【讨论】:

以上是关于@ngrx Effect 没有第二次运行的主要内容,如果未能解决你的问题,请参考以下文章

在调度一个动作和 NgRx 效果之前执行多个 API 调用

NgRx @Effect 与 createEffect

在ngrx/effect中访问存储的正确方法

如何在ngrx/effect(redux-observable)中调度多个动作?

Cordova + ngrx/effect fire and forget long running 方法冻结 UI

ngrx effect 多次调用observer,但只调度了一个action