Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing root reducer in @ngrx/store 4.0

In @ngrx/store 2.0 we could provide the root reducer as a function and from there we split our logic inside the application. After I updated to @ngrx/store 4.0 I cannot use this feature any more from what I can see the reducers need to be a map of reducers which will create objects under the same keys in the state. Is there a way to use the old behavoir in @ngrx/store 4.0 In my state components are aware one of another and I need to be able to split my state dynamically also I need to be able to dispatch actions to the right reducer in my own way. Also app is splitted in multiple lazy loaded routes which in some cases reuse the data from another feature.

 StoreModule.provideStore(reducer, {
      auth: {
        loggedIn: true
      }
    })

StoreModule.forRoot(reducers, {
      initialState: {
        auth: {
          loggedIn: true
        }
      }
    })

I need reducers to be a function which gets the full state and dispatches it to the correct reducer, Is there a way to achieve this behavior?

like image 286
Nicu Avatar asked Jul 20 '17 16:07

Nicu


People also ask

What is the use of reducer in ngrx?

Reducers in NgRx are responsible for handling transitions from one state to the next state in your application. Reducer functions handle these transitions by determining which actions to handle based on the action's type. Reducers are pure functions in that they produce the same output for a given input.

What is a good ngrx implementation?

In good a NgRx implementation Container components must depend only on the Store for state (selectors and actions). If an application uses routes / navigation, the routing becomes an essential part of your application state. Without incorporating Router in your Store, container components can’t depend on store alone.

How do reducer functions work?

Each reducer function takes the latest Action dispatched, the current state, and determines whether to return a newly modified state or the original state. This guide shows you how to write reducer functions, register them in your Store, and compose feature states. There are a few consistent parts of every piece of state managed by a reducer.

How to make router state state in ngrx-router-store?

We can recourse to ngrx-router-store with custom RouterStateSerializer<T> to give us routing state in a form we like <T= MergedRoute> To make router state {params, queryParams, data}: MergedRoute a part of our centralized NgRx store state ['router'], we will write a module that can simply be included in your App’s root module


3 Answers

After I had a second look over ngrx repo I figured it out. To achieve the wanted result we need to replace the @ngrx/store reducer factory with a new implementation. I injected a new reducer factory and right now the application works as before. Simple code sample on how to replace the reducer factory it.

// This factory replaces @ngrx combine reducers so we can manage how we split the keys inside the state
export function combineReducersFactory(
    reducers: any,
    initialState: any = {}
): ActionReducer<any, Action> {
    return function combination(state = initialState, action) {
        const nextState: any = reducers(state, action);
        return nextState !== state ? nextState : state;
    };
}

export const NG_RX_STORE_PROVIDER = [
    StoreModule.forRoot(rootReducer, createEmptyState()),
];

export const NG_RX_REDUCER_FACTORY = [
    {
        provide: REDUCER_FACTORY,
        useFactory: () => combineReducersFactory
    }
];

@NgModule({
    imports: [
        ...NG_RX_STORE_PROVIDER
    ],
    declarations: [...APP_COMPONENTS, ...AG_GRID_COMPONENTS],
    providers: [...NG_RX_REDUCER_FACTORY]
})
export class AppModule {
}
like image 102
Nicu Avatar answered Nov 15 '22 04:11

Nicu


You can set up a meta reducer to receive every event and manipulate the state from its root. Here is an example way to set it up:

const myInitialState = {
  // whatever you want your initial state to be
};

export function myMetaReducer(
  reducer: ActionReducer<RootStateType>
): ActionReducer<RootStateType> {
  return function(state, action) {
    if (iWantToHandleThisAction) {
      state = doWhatIWantWith(state);
    }
    return reducer(state, action);
  };
}

@NgModule({
  imports: [
    StoreModule.forRoot(myInitialState, { metaReducers: [myMetaReducer] })
  ]
})
export class AppModule {}
like image 41
Eric Simonton Avatar answered Nov 15 '22 02:11

Eric Simonton


The StoreModule forRoot() function accepts a reducerFactory which can be used as follows:

export function myReducerFactory(reducers: any, initState: any) {
  return (state = myInitialState, action) => myCustomReducer(state, action);
}

@NgModule({
  // ...
  imports: [
    StoreModule.forRoot(null, { reducerFactory: myReducerFactory })
  ]
  // ...
})
export class AppModule {
}
like image 33
Stephen Paul Avatar answered Nov 15 '22 03:11

Stephen Paul