0

I am encountering an issue with my code, using ngRx. Since the project is huge and it is more of a design question, I'm sorry I'm not providing a minimal and reproducting example.

I have a project with this structure :

AppModule
    PrimaryOutletModule
        SidenavComponent
        HeaderComponent

ExploitationComponentsModule [lazy loaded in AppRouting]
    MapComponent
    MaService

ServicesModule [imported in AppModule]
    HttpServicesModule
        ExploitationServicesModule
            ExploitationService

In this structure, I add this module to AppModule :

@NgModule({
  imports: [
    StoreModule.forRoot(exploitationReducers),
  ]
})
export class ExploitationStoreModule { }

Without any issue, all of my code works well. But when I add it to PrimaryOutletModule, ExploitationComponentsModule, and ExploitationServicesModule, and remove it from AppModule it stops working.

I want to remove it from the AppModule to avoid creating globally accessible stores (I want to give them meaningful scopes)

My first thought is to log the select and dispatch events, and when I do so, I see that events aren't caught. After adding this to the module :

constructor() { console.log('Store module instance created'); }

I see two instances. Following this SOF question, I realize that I have to use the forRoot method of the StoreModule.

But since my ExploitationStoreModule is already using it, I look for a solution and stumble upon this SOF question, saying that lazy loaded modules are creating new instances of modules.

If I understood it correctly, I am using forRoot twice, resulting in two instances of my ExploitationStoreModule.

Since I want to give correct scopes to my modules and don't let them access stores they don't have business with (for instance, ExploitationModule should not have access to SupervisionStore), I would like to not be forced to import all of my Store modules into my AppModule.

That brings the question : how should one declare stores in an application so that they aren't global and only provided in their respective modules ?

1 Answers1

1

You can use storeModule.forFeature in the feature modules. But the state will become available to your whole application when the module is being loaded.

Some extra resources:

A store holds the whole state tree of your application, and the following the best practices you should only have one store (there are edge cases where performance might be an issue where you would need multiple stores, I linked to the redux docs which have a great explanation).

If you import your store into your component with eg Store<FooState>, typescript only knows about the FooState but in fact your store holds your whole application's state, eg also BarState.

But personally I don't need to access the store inside my components because I'm using selectors, which doesn't really need the store type. For example this.store.select(selectEmployees).

timdeschryver
  • 14,415
  • 1
  • 19
  • 32
  • So that means once the `Exploitation` module is loaded, if I add a `ExploitationStore` to my `SupervisionComponent`, it will have access to it ? Does that mean you can't scope a store to a single module (other than the app module) ? Anyway, +1 for the information –  Sep 21 '18 at 09:52
  • A store holds the whole state tree of your application, and the following the best practices you should only have one store (there are edge cases where performance might be an issue where you would need multiple stores, I linked to the redux docs which have a great explanation). – timdeschryver Sep 21 '18 at 09:56
  • If you import your store into your component with eg `Store`, typescript only knows about the `FooState` but in fact your store holds your whole application's state, eg also `BarState`. – timdeschryver Sep 21 '18 at 09:57
  • But personally I don't need to access the store inside my components because I'm using selectors, which doesn't really need the store type. For example `this.store.select(selectEmployees)` – timdeschryver Sep 21 '18 at 09:58
  • 1
    Okay, so best practice is a single store, not several ones ? And I understand that components only understand the `State` provided, but I would like to prevent devs from importing states that aren't related to the module they're in. Seems like it isn't possible, bummer ... Thank you for all that information though, very helpful ! –  Sep 21 '18 at 10:00