Reputation: 406
I've been struggling for 2 days to compose states of a featureA ("scenarios") module and a nested featureB ("intents") module.
Here is the desired structure of my state (structure 1):
{
authentication: { ... },
router: { ... },
scenarios: {
resources: { ids: { ... }, entities: { ... } },
intents: {
resources: { ids: { ... }, entities: { ... } }
}
}
}
I'd be happy also with (structure 2):
{
authentication: { ... },
router: { ... },
scenarios: { ids: { ... }, entities: { ... } },
intents: { ids: { ... }, entities: { ... } },
}
Although it doesn't reflect the structure of my modules.
The problem with structure 1 is that scenarios/reducers/index.ts
exposes a ActionReducerMap
, scenarios/modules/intents/reducers/index.ts
also exposes a ActionReducerMap
and I don't know how to compose them. Everything I tried doesn't even compile because of type conflicts.
The problem with structure 2 is that the intents
part of the state keeps being dropped out of the state because of the IntentsModule
not being loaded at first page load and other reducers of the app doing their job.
Here is the code:
/scenarios/scenarios.module.ts:
import { reducers, getInitialState } from './reducers';
@NgModule({
imports: [
...,
ScenariosRoutingModule,
StoreModule.forFeature('scenarios', reducers, { initialState: getInitialState }),
EffectsModule.forFeature([ScenariosEffects]),
],
})
export class ScenariosModule {}
/scenarios/reducers/index.ts:
import * as fromRoot from '../../../app.reducers';
import * as fromScenarios from './scenarios.reducers';
import * as fromIntents from '../modules/intents/reducers';
export interface ScenariosState {
resources: fromScenarios.State;
intents: fromIntents.IntentsState;
}
export interface State extends fromRoot.State {
scenarios: ScenariosState;
}
export const reducers: ActionReducerMap<ScenariosState> = {
resources: fromScenarios.reducer,
intents: fromIntents.reducers, <-- This is the part with types conflicts
};
/scenarios/modules/intents/intents.module:
import { reducers, getInitialState } from './reducers';
@NgModule({
imports: [
...,
IntentsRoutingModule,
StoreModule.forFeature('intents', reducers, { initialState: getInitialState }), <-- Also this part seems to add 'intents' as a top-level property of state
EffectsModule.forFeature([IntentsEffects]),
],
})
export class IntentsModule {}
/scenarios/modules/intents/reducers/index.ts:
import * as fromIntents from './intents.reducers';
export interface IntentsState {
resources: fromIntents.State;
}
export interface State {
intents: IntentsState;
}
export const reducers: ActionReducerMap<IntentsState> = {
resources: fromIntents.reducer,
};
export function getInitialState(): IntentsState {
return {
resources: fromIntents.initialState,
};
}
Upvotes: 2
Views: 1727
Reputation:
import
and export
the structure 2
IntentsModule
in the root AppModule
. import
the ScenariosModule
after the IntentsModule
in the root AppModule
. Do not nest various IntentsModules
under the ScenariosModules
. Instead create separation and flatten your project structure as much as possible this is inherently required by structure 2
.
I've found that a good approach for most situations with the exception of Auth related features is to create two modules per feature to be lazily loaded together yet decoupling state-management from the user-interface yet these corresponding modules should share an API
of the same shape i.e:
FrameworkLayoutModule
and FrameworkStoreModule
) and (AuthModule
). Subsequently, reusable features may be lazily loaded by a SecureModule
or a PublicModule
as needed.
Upvotes: 2
Reputation: 2137
This problem with use 'intents' store in two modules. And NgRx can`t create 'intents' store twice.
solution 1
remove 'intents' from scenarios.module or from intents.module if it dont use there.
solution 2
move 'intents' store into StoreModule.forRoot or into scenarios and intents parent module.
Upvotes: 0