Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngrx reducer not firing after action dispatched

Tags:

angular

ngrx

I'm finding that my reducer function does not fire when I dispatch an action to my store

I have a feature module with actions that work fine

The issue I'm having is with the layout state which is the only state I'm registering with the root state.

This is how I'm initialising the app:

//Root
import * as fromLayout from '../core/store/reducers/layout.reducer';
import * as layoutActions from '../core/store/actions/layout.actions';
import { ActionReducerMap, createSelector } from '@ngrx/store';
import { ActionReducer } from 'ngx-bootstrap/mini-ngrx';
//Interface to hold all states, top level state interface is just a map of keys to inner state types.
export interface Root {
  readonly layout: fromLayout.State
}
export type RootActions =  layoutActions.Actions;

//Get reducers
export const initialState = {
  layout: fromLayout.reducer(undefined, {} as layoutActions.Actions)
}

export interface State {
    root: Root;
  }
//Make sure below is not a function expression
  export function rootReducer(state: Root = initialState, action: RootActions){
    return {
        layout: fromLayout.reducer(state.layout, {} as layoutActions.Actions)
    };
  };

  export const reducers: ActionReducerMap<State> = {
    root: rootReducer
  };

In the app.module.ts

  import { reducers } from './reducers/';//This points to -> const reducers: ActionReducer

 StoreModule.forRoot(reducers),
    StoreDevtoolsModule.instrument({maxAge: 25}),
    EffectsModule.forRoot([])

My layout.actions.ts

import { Action } from '@ngrx/store';

export const OPEN_SIDENAV = '[Layout] Open Sidenav';
export const CLOSE_SIDENAV = '[Layout] Close Sidenav';
export const CURRENT_BLOG_ID = '[Layout] Current Blog ID';
export class OpenSidenav implements Action {
  readonly type = OPEN_SIDENAV;
}

export class CloseSidenav implements Action {
  readonly type = CLOSE_SIDENAV;
}

export class CurrentBlogID implements Action {
  readonly type = CURRENT_BLOG_ID;
  constructor(public payload:string){
    console.log(this.payload)
  }
}

export type Actions = OpenSidenav | CloseSidenav | CurrentBlogID;

layout.reducers.ts

import * as layout from '../actions/layout.actions';

export interface State {
  showSidenav: boolean;
  currentBlogID:string
}

const initialState: State = {
  showSidenav: false,
  currentBlogID:''
};

export function reducer(state = initialState, action: layout.Actions): State {
  switch (action.type) {
    case layout.CLOSE_SIDENAV:
      return {
        ...state,
        showSidenav: false,
      };

    case layout.OPEN_SIDENAV:
      return {
        ...state,
        showSidenav: true,
      };
      case layout.CURRENT_BLOG_ID:
      console.log(action.payload)
      return handleCurrentBlogID(state, action)
    default:
      return state;
  }
}

function handleCurrentBlogID(state, action){
  console.log(action.payload)
  let newState = {
    ...state,
    currentBlogID: action.payload,
  }
  return newState
}
export const getShowSidenav = (state: State) => state.showSidenav;

How I'm dispatching to the store:

import { State } from '../../reducers';//This is root state
export class HomeComponent {
  constructor(private store: Store<State>) {}

  onBlogSelected(id){

    this.store.dispatch(new CurrentBlogID(id))
  }
}
like image 357
Rasta Avatar asked Dec 01 '25 13:12

Rasta


1 Answers

In rootReducer you are calling the layout reducer and passing its return value not function itself. It should be like below

return {
    layout: fromLayout.reducer
};
like image 195
Hikmat G. Avatar answered Dec 04 '25 04:12

Hikmat G.