如何派发空动作?

How to dispatch an empty action?

我正在使用 ngrx/effects

如何调度空动作?

我现在是这样的:

 @Effect() foo$ = this.actions$
    .ofType(Actions.FOO)
    .withLatestFrom(this.store, (action, state) => ({ action, state }))
    .map(({ action, state }) => {
      if (state.foo.isCool) {
        return { type: Actions.BAR };
      } else {
        return { type: 'NOT_EXIST' };
      }
    });

因为我必须 return 一个动作,所以我使用 return { type: 'NOT_EXIST' };

有更好的方法吗?

我使用过类似的未知操作,但通常是在减速器单元测试的上下文中。

如果您对在效果中做同样的事情感到不安,您可以使用 mergeMapObservable.of()Observable.empty() 有条件地发出一个动作:

@Effect() foo$ = this.actions$
  .ofType(ChatActions.FOO)
  .withLatestFrom(this.store, (action, state) => ({ action, state }))
  .mergeMap(({ action, state }) => {
    if (state.foo.isCool) {
      return Observable.of({ type: Actions.BAR });
    } else {
      return Observable.empty();
    }
  });

我会按以下方式进行:

@Effect() foo$ = this.actions$
    .ofType(Actions.FOO)
    .withLatestFrom(this.store, (action, state) => ({ action, state }))
    .filter(({ action, state }) => state.foo.isCool)
    .map(({ action, state }) => {
      return { type: Actions.BAR };
    });

我正在寻找的解决方案涉及使用 @Effect({ dispatch: false })

  @Effect({ dispatch: false })
  logThisEffect$: Observable<void> = this.actions$
    .ofType(dataActions.LOG_THIS_EFFECT)
    .pipe(map(() => console.log('logThisEffect$ called')));

选择的答案不再适用于 rxjs6。所以这是另一种方法。

虽然我更喜欢在另一个答案中描述的大多数情况下进行过滤,但使用 flatMap 有时会很方便,尤其是当你在做复杂的事情时,对于过滤函数来说太复杂了:

import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { flatMap } from 'rxjs/operators';
import { EMPTY, of } from 'rxjs';

@Injectable()
export class SomeEffects {
  @Effect()
  someEffect$ = this._actions$.pipe(
    ofType(SomeActionTypes.Action),
    flatMap((action) => {
      if (action.payload.isNotFunny) {
        return of(new CryInMySleepAction());
      } else {
        return EMPTY;
      }
    }),
  );

  constructor(
    private _actions$: Actions,
  ) {
  }
}

从 ngrx 8 开始,如果您尝试分派一个空操作,您将得到一个 运行 时间错误,所以我认为只需将它们过滤掉,这样它们就不会被分派。

@Effect() foo$ = this.actions$.pipe(
    ofType(Actions.FOO),
    withLatestFrom(this.store, (action, state) => ({ action, state })),
    map(({ action, state }) => {
      if (state.foo.isCool) {
        return { type: Actions.BAR };
      }
    }),
    filter(action => !!action)
);

如果您不想派发一个动作,那么只需将 dispatch 设置为 false:

 @Effect()
  foo$ = createEffect(() =>
    this.actions$.pipe(
      ofType(Actions.FOO),
      map(t => [])
    ),
    { dispatch: false }
  );

"rxjs": "~6.6.6" 中,平面图已被合并图描述,我们可以使用相同的行为

import { map, switchMap, catchError, mergeMap } from 'rxjs/operators';
import { of, EMPTY } from 'rxjs';

    addCategorie$ = createEffect(() =>
        this.actions$.pipe(
          ofType(ADD_CATEGORY),
          mergeMap((category) => this.categoryService.post(category.isCategoryOrVendor, category.model)
            .pipe(
              mergeMap(() => {
                this.backService.back();
                return EMPTY;
              }),
              catchError((error) => of(CATEGORY_ERROR(error)))
            )
          )
        )
      );