Search code examples
angularreduxngrx

Angular NgRx dispatching action method


So we have this ordinary effect doSomething. What is the official way to dispatch another action, named doSomethingElse? The documentation doesn't really say anything about the right way. In the end there might not be much difference, yet I don't really like the fact I could use dispatch: false in like 95% of my codebase.

Dispatching action by using dispatch: false:

doSomething$ = createEffect(() =>
this.actions$.pipe(
  ofType(AuthActions.doSomething),
  map(() => AuthActions.doSomethingElse())
));

doSomethingElse$ = createEffect(
() =>
  this.actions$.pipe(
    ofType(AuthActions.doSomethingElse),
    tap(() => console.log('it works!'))
  ),
{ dispatch: false });

Dispatching action without dispatch: false:

doSomething$ = createEffect(
() =>
  this.actions$.pipe(
    ofType(AuthActions.doSomething),
    tap(() => {
      this.store.dispatch(AuthActions.doSomethingElse());
    })
  ),
{ dispatch: false });

doSomethingElse$ = createEffect(
() =>
  this.actions$.pipe(
    ofType(AuthActions.doSomethingElse),
    tap(() => console.log('it works!'))
  ),
{ dispatch: false });

Both solutions work, yet I am not sure which is the correct way of using NgRx.


Solution

  • Second one is not recommended.

    The following code would complain if you didn't map to an action whereas putting { dispatch: false } removes this check and should only be used for side effects like navigation, setting localStorage etc.

    doSomething$ = createEffect(() =>
    this.actions$.pipe(
      ofType(AuthActions.doSomething),
      map(() => AuthActions.doSomethingElse())
    ));
    

    Your example isn't clear on why two actions are needed where one would do.

    If you want a general action logger the following will work:

    /**
     * Log all actions in the console
     */
    
    export function logger(
      reducer: ActionReducer<RootStoreState.State>
    ): ActionReducer<RootStoreState.State> {
      return (state, action) => {
        const result = reducer(state, action);
        if (action.type.startsWith("[")) { <----FILTER TO ONLY USER CREATED ACTIONS (i.e. not router)---------
          console.groupCollapsed(action.type);
          console.log("prev state", state);
          console.log("action", action);
          console.log("next state", result);
          console.groupEnd();
        }
    
        return result;
      };
    }
    

    and in app.module.ts

    export const metaReducers: MetaReducer<any>[] = !environment.production
      ? [logger]
      : [];
    
    @NgModule({
      imports: [
        ...
        StoreModule.forRoot(ROOT_REDUCERS, {
          metaReducers, <--------------------------------------KEY LINE-----------
          runtimeChecks: {
            strictStateImmutability: true,
            strictActionImmutability: true,
            strictStateSerializability: true,
            strictActionSerializability: true
          }
        }),
        ...