如何在ngrx / effect中调度多个动作?

mr_*_*ash 5 javascript typescript ngrx angular ngrx-store

我正在使用Angular 6,ngrx / store。我有负责更新事物的效果。取决于某些逻辑,我想调度不同的操作。如果我使用switchMapinsted of有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;
    })
  );
Run Code Online (Sandbox Code Playgroud)

Kim*_*ern 16

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

代替:

input:  --a-------a------>
output: --[b,c]---[b,c]-->
Run Code Online (Sandbox Code Playgroud)

你应该做:

input:  --a-------a------>
output: --b-c-----b-c-->
Run Code Online (Sandbox Code Playgroud)

平坦化可观察到的阵列到每个元件的观测量,则可以使用运营商之一mergeMapswitchMapexhaustMap。在大多数情况下,mergeMap将是正确的选择。如果您想了解有关这些运算符的更多信息,请查看此答案

@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)
    ]
  })
);
Run Code Online (Sandbox Code Playgroud)


Igo*_*ino 5

我也遇到过同样的情况(假设 NgRx 10 或更高),我有不同的观点,更基本的方式如何使用效果。在一个地方(特别是在单个效果中)顺序触发多个操作是反模式。从本质上讲,在 NgRx 中保持动作和潜在减少的应用程序状态的一般流程一致非常重要。正如 NgRx 架构所预见的那样。

遵循3 个效果规则将有助于避免困难的情况:

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

这样,它可以帮助您遵循关注点分离设计模式,这当然也可以帮助您使 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}
);
Run Code Online (Sandbox Code Playgroud)