@ngrx/store combine multiple reducers from feature module
Your setup is almost correct.
In the createFeatureSelector
function you declare a feature key in the root of the store, 'exercises' in the example. So, you are going to select store.exercises.exercises.id
for example and feature selector is just a shortcut to store.exercises
.
However, in the StoreModule.forFeature('training', trainingReducers)
call you defined 'training' as the root key for your feature module.
The correct setup could look like this:
export const featureReducersMap = {
exercise: exerciseReducer,
anyOtherKey: anyOtherReducer
};
StoreModule.forFeature('myFeatureModule', featureReducersMap);
export interface FeatureState{
exercise: string;
anyOtherKey: number;
}
Then write selectors like:
export const featureSelector = createFeatureSelector<FeatureState>('myFeatureModule');
export const exerciseSelector = createSelector(
featureSelector,
(state: FeatureState) => state.exercise
);
It is recommended to store the feature key in the variable instead of hardcoding it.
With new feature createFeature you can do it easier.
- Add feature to AppState interface
export interface AppState {
yourFeature: FeatureInterface
}
- Create some feature inside module. For example
export interface State {
key: string;
}
export const initialState: State = {
key: ''
};
export const feature = createFeature({
name: 'module',
reducer: createReducer(
initialState
)
});
export const {
name,
reducer
} = feature;
- Combine all your reducers from module
import * as fromGreatFeature from './store/great-feature/great-feature.reducer';
import * as fromEntity from './store/entity/entity.reducer';
import * as fromModule from './store/module/module.reducer';
export interface ScheduleState {
module: fromModule.State; // <- from example
entity: fromEntity.State;
greatFeature: fromGreatFeature.State;
}
export const reducers = combineReducers({
module: fromModule.reducer, // <- from example
entity: fromEntity.reducer,
greatFeature: fromGreatFeature.reducer
});
- Make separate file and define store module or make it inside main module file
export const yourFeature = createFeature<AppState>({
name: 'yourFeature', // name from interface
reducer: reducers // combined reducers
});
export const {
name,
reducer
} = yourFeature;-----------------
|
|
@NgModule({ |
imports: [ |
StoreModule.forFeature(yourFeature),
EffectsModule.forFeature([Effects, Effects, Effects])
],
exports: [StoreModule, EffectsModule]
})
export class LegendaryStoreModule {}
@NgModule({
declarations: [
SomeComponent
],
imports: [
SharedModule,
LegendaryRoutingModule,
LegendaryStoreModule, // <- your store module
],
exports: [
]
})
export class YourLegendaryModule {}
- And selectors. Function
createFeature
automatically generated to you selectors
export const getSomeThing = createSelector(
yourFeature.selectYourFeatureModuleState, // <- main feature state
fromModule.selectSome // <- nested state
);
I can give you an example how I did it. I used an index.ts to bundle all other reducers from within the module like this:
module/reducers/index.ts
import * as fromRoot from '../../../reducers';
import * as fromSearch from './search';
import * as fromUserDetail from './user-detail';
import * as fromDetailBase from './base';
export interface UserModuleState {
search: fromSearch.State;
detail: fromUserDetail.State;
detailBase: fromDetailBase.State;
}
export interface State extends fromRoot.State {
userModule: UserModuleState;
}
export const reducers = {
search: fromSearch.reducer,
detail: fromUserDetail.reducer,
detailBase : fromDetailBase.reducer
};
export const selectUserModuleState = createFeatureSelector<UserModuleState>('userModule');
export const selectSearchState = createSelector(
selectUserModuleState, (state: UserModuleState) => state.search
);
export const getSearchLoading = createSelector(selectSearchState, fromSearch.getLoading);
export const getSearchEntities = createSelector(selectSearchState, fromSearch.getEntities);
module/user.module.ts
import { reducers } from './reducers';
@NgModule({
imports: [
...
StoreModule.forFeature('userModule', reducers)
],
...
})
export default class UserModule { }