Moein Hosseini
Moein Hosseini

Reputation: 1596

Why my reducer is called multiple times when I dispatch an action after importing store for feature?

I'm new to ngrx and I'm trying to have a state for each of my feature modules and also a state for app module. First, I registered StoreModule and it's effects in app.module.ts like this:

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    StoreModule.forRoot({app: fromApp.reducer}),
    EffectsModule.forRoot([AppEffectsService])
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Then I created a module called home with it's reducer and and effects service and used them like this:

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    HomeRoutingModule,
    StoreModule.forFeature(fromHome.homeFeatureKey, fromHome.reducer),
    EffectsModule.forFeature([HomeEffectsService]),
  ]
})
export class HomeModule { }

I put a console.log in my home reducer and saw every time I dispatch an action, I see the log twice per action! I don't now why my reducer is called twice per dispatch. And even when I add store to more modules, I see the repeated logs more.

The reducer looks like this:


const homeReducer = createReducer(
    initialHomeState,
    on(HomeActions.loadOrderTypesSuccess, (state, { orderTypes }) => ({ ...state, orderTypes })),
);

export function reducer(state: HomeState | undefined, action: Action) {
    console.log(action.type);
    return homeReducer(state, action);
}

And this is my effect:

  loadOrderTypes$ = createEffect(() => this.actions$.pipe(
    ofType(HomeActions.loadOrderTypes),
    mergeMap(() => from(this.dataService.getOrderTypes())
      .pipe(
        map(orderTypes => HomeActions.loadOrderTypesSuccess({ orderTypes })),
        catchError(error => of(HomeActions.loadOrderTypesFailure({ error }))),
      )
    )
  ));

The creation of actions:

export const loadOrderTypes = createAction(
    '[Home Page] Load order type start'
);

export const loadOrderTypesSuccess = createAction(
    '[Home Page] Load order type success',
    props<{ orderTypes: OrderType[] }>()
);

export const loadOrderTypesFailure = createAction(
    '[Home Page] Load order type failure',
    props<{ error: any }>()
);

After dispatching the action, the log is:

@ngrx/store/init
15:23:36.470 app.reducer.ts:22 @ngrx/effects/init
15:23:36.505 core.js:38781 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
15:23:36.608 app.reducer.ts:22 @ngrx/store/update-reducers
15:23:36.609 home.reducer.ts:35 @ngrx/store/update-reducers
15:23:36.644 app.reducer.ts:22 [Home Page] Load order type start
15:23:36.644 home.reducer.ts:35 [Home Page] Load order type start
15:23:36.761 client:52 [WDS] Live Reloading enabled.
15:23:37.743 app.reducer.ts:22 [Home Page] Load order type success
15:23:37.744 home.reducer.ts:35 [Home Page] Load order type success

I want my reducer to be called once. What am I doing wrong?

Upvotes: 4

Views: 2909

Answers (2)

LAURYNAS PETRAUSKAS
LAURYNAS PETRAUSKAS

Reputation: 11

I was upgrading effects to v8 ngrx, and what called my issue, was in effects.

When deleted it @Effect(), the problem was solved.

Bad:

@Effect()
test$ = createEffect(() => this.actions$.pipe(...

Good:

test$ = createEffect(() => this.actions$.pipe(...

Upvotes: 0

timdeschryver
timdeschryver

Reputation: 15487

An action is dispatched to all reducers, this is by design.

We can't know which reducers to call because it's perfectly fine to modify state based on an action from another module.

Upvotes: 2

Related Questions