0
votes

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.

2

2 Answers

0
votes

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
      }
    }),
    ...
-1
votes

I will put it in old style because I didnt migrate yet to new way of ngrx but its also the same.

Actions.ts

export enum AuthActionTypes {
    SIGNUP = '[AUTH] SIGNUP',
    SIGNUP_SUCCESS = '[AUTH] SIGNUP_SUCCESS',
}

export class Signup implements Action {
    readonly type = AuthActionTypes.SIGNUP;
    constructor(public payload: any) { }
}
export class SignupSuccess implements Action {
    readonly type = AuthActionTypes.SIGNUP_SUCCESS;
}

export type AuthActions =
    Signup |
    SignupSuccess;

Effect

@Effect()
    signup$: Observable<Action> = this.actions$.pipe(
        ofType(AuthActionTypes.SIGNUP),
        map((action: Signup) => action.payload),
        map((payload) => {
              // whatever
            return new SignupSuccess(); // this come from AuthActions inner // action.ts, you are dispaching SignupSuccess();
        }),

@Effect()
    signupSuccess$: Observable<Action> = this.actions$.pipe(
        ofType(AuthActionTypes.SIGNUP_SUCCESS),
        map((action: Signup) => action.payload),
        map((payload) => {
              // whatever
            return new XAction(); 
        }),
```