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

Posted

技术标签:

【中文标题】如何在ngrx/effect(redux-observable)中调度多个动作?【英文标题】:How to dispatch multiple actions in ngrx/effect (redux-observable)? 【发布时间】:2018-11-10 18:19:41 【问题描述】:

我正在使用 Angular 6,ngrx/store。我有这样的效果,负责更新东西。取决于我想调度不同动作的一些逻辑。如果我使用switchMap insted 和map 有什么区别?

这是我尝试过的,但它不起作用:

 @Effect()
  dispathMultipleActions$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    map(() => 
      const actions: Action[] = [];
      const array = [1, 2, 3, 4, 5];
      array.forEach(item => 
        if (item > 3) 
          actions.push(new DeleteAction(item));
         else 
          actions.push(new ChangeAction(item));
        
      );
      return actions;
    )
  );

【问题讨论】:

我想你想尝试 switchMap 的函数,该函数返回内部操作的 Observable.concat。这将展平操作列表并考虑顺序。 【参考方案1】:

效果会转换一系列动作,因此您有一个动作流作为输入和输出。在您的示例中,您将一个动作映射到一个动作数组。动作数组流不是有效的输出类型。您需要展平该数组,这意味着您不会将数组本身发送到输出流中,而是将其每个元素发出。

代替:

input:  --a-------a------>
output: --[b,c]---[b,c]-->

你应该这样做:

input:  --a-------a------>
output: --b-c-----b-c-->

为了将数组的 Observable 展平为每个元素的 Observable,您可以使用运算符mergeMapswitchMapexhaustMap 之一。在大多数情况下,mergeMap 将是正确的选择。如果您想了解有关这些运算符的更多信息,请查看此answer。

@Effect()
register$: Observable<Action> = this.actions$.pipe(
  ofType(AuthActionTypes.REGISTER_REQUEST),
  mergeMap((action: RegisterRequest) => 
    // check for register request success
    return [
      new RegisterSuccess(),
      new LoginRequest(action.payload)
    ]
  )
);

【讨论】:

您好,它似乎不再适用于 NGRX 10:一旦我放置一个数组以返回 2 个操作(单独工作),我有一个 TS 错误说类型 [] 不兼容带有“动作”... 完成我的评论:解决方案似乎是:`this.store$.dispatch(RegisterSuccess()); return LoginRequest(action.payload); 您能否澄清一下-在这种情况下,为什么动作数组被认为是可观察的数组?行动!= 可观察的。虽然我也使用这种模式并且它按预期工作【参考方案2】:

我有同样的情况(假设 NgRx 10 或更高),我有不同的观点,更基本的方式如何使用效果。在一个地方按顺序触发多个动作,特别是在单个效果内,是反模式。 从本质上讲,重要的是保持一致的general flow of application state in NgRx 行动和潜在减少。正如 NgRx 架构所预见的那样。

关注the 3 effect rules 将有助于避免困难情况:

    将效果命名为效果的名称 让你的效果只做一件事 只发出一个动作

这样,它可以帮助您遵循separation of concerns 设计模式,这当然也可以帮助您使 NgRx 效果变得更加可单元测试。

回到您的示例,您可以通过中间代理操作简单地将您想做的事情(2 个额外操作)解耦。

在您的情况下,您似乎甚至不需要您的原始效果dispathMultipleActions$,除非出现特殊逻辑。 (也许,它可能属于一个状态 Reducer,它更具单元测试性)。

假设 ActionTypes.UpdateSomething 已经有一个数组有效负载对象,您可以将您的 dispathMultipleActions$ 拆分为单个,因此您可以执行以下操作:

@Effect()
deleteAction$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    concatMap(from(new Promise((array) => 
        array.forEach(item => 
            if (item > 3) 
                //do something
            
        );
    ))),
    dispatch: false
);

@Effect()
changeAction$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    concatMap(from(new Promise((array) => 
        array.forEach(item => 
            if (item <= 3) 
                //do something
            
        );
    ))),
    dispatch: false
);

【讨论】:

以上是关于如何在ngrx/effect(redux-observable)中调度多个动作?的主要内容,如果未能解决你的问题,请参考以下文章

NgRx @Effect 与 createEffect

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

@ngrx Effect 没有第二次运行

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

Angular 5 ngrx Effect 没有导出成员'ofType'

如何处理来自 ngrx effect 的 catch 块的错误并将其发送到组件中?