Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

angular

rxjs

ngrx

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?

like image 726
Moein Hosseini Avatar asked Sep 18 '25 06:09

Moein Hosseini


1 Answers

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.

like image 125
timdeschryver Avatar answered Sep 20 '25 22:09

timdeschryver