Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register ngrx sub features (StoreModule.forFeature()) for my angular app?

Tags:

angular

ngrx

Following is my angular app structure

app.module.ts
 -- StoreModule.forRoot()
    mainboard.module.ts
        --StoreModule.forFeature('mainboard', reducer)

            subFeature1.module.ts
            subFeature2.module.ts
            subFeature3.module.ts

    dashboard1.module.ts
        --StoreModule.forFeature('dashboard1', reducer)

            subFeature1.module.ts
            subFeature2.module.ts
            subFeature3.module.ts
            subFeature4.module.ts
            subFeature5.module.ts

    dashboard2.module.ts
        --StoreModule.forFeature('dashboard2', reducer)

            subFeature1.module.ts
            subFeature2.module.ts

    dashboard3.module.ts
        --StoreModule.forFeature('dashboard3', reducer)

            subFeature1.module.ts
            subFeature2.module.ts
            subFeature3.module.ts
            subFeature4.module.ts

    dashboard4.module.ts
        --StoreModule.forFeature('dashboard4', reducer)

            subFeature1.module.ts
            subFeature2.module.ts


So the requirement is to have store for subfeatures.

Like this:

app.module.ts
 -- StoreModule.forRoot()
    mainboard.module.ts
        --StoreModule.forFeature('mainboard', reducer)

            subFeature1.module.ts
              --StoreModule.forFeature('subFeature1', reducer)

            subFeature2.module.ts
              --StoreModule.forFeature('subFeature1', reducer)
            subFeature3.module.ts
              --StoreModule.forFeature('subFeature1', reducer)


...


HOW CAN I ACHIEIVE SUCH A HIERARCHY FOR MY NGRX/STORE ?

app.module is there all the dashboards are placed.

dashboard-x.modules are the places where all the navs/ items are placed.

and inside each dashboards sub features are included.

So my question is about how to register subFeatures with StoreModule.forFeature()?

Or do I need to make stores for each dashboards (StoreModule.forRoot()) and then StoreModule.forFeature() for each subFeatures? (if so then how may I be able to register it inside the app's StoreModule.forRoot())

NOTE

Currently I'm registering all of the subfeatures as forFeature.('subfeturename', reducer)

But the problem with this is that when I have a look at my state tree (Redux devtools) it is not following the above store tree structure. Since all the sub features are getting registered as forFeature() all of them are showing as properties (ie, they are not getting nested as expected). What I want instead is that I want to have them nested inside my state tree.

So if I have a look at my state tree I can see nested state Like this:

app
    mainboard(open)
          subFeature1
          subFeature2
          subFeature3

    dashboard1(closed)

    dashboard2(open)
          subFeature1
          subFeature2

    dashboard3(closed)

    dashboard4(closed)

//open and closed means expand and collapsed tree

Remember, each level (app > dashboard1 > subfeature) has different properties which needs to be managed by stores. So a store is necessary for each level.

like image 659
mx_code Avatar asked May 19 '20 10:05

mx_code


People also ask

What is NgRx feature state?

There are three main building blocks of global state management with @ngrx/store : actions, reducers, and selectors. For a particular feature state, we create a reducer for handling state transitions based on the dispatched actions, and selectors to obtain slices of the feature state.

Where is NgRx data stored?

Where Does NgRx Store Data? NgRx stores the application state in an RxJS observable inside an Angular service called Store. At the same time, this service implements the Observable interface.

Why we use NgRx store in Angular?

NgRx implements the Flux-Pattern. At a high level, it helps you unify all events and derive a common state in your Angular app. With NgRx, you store a single state and use actions to express state changes. It is ideal for apps with many user interactions and multiple data sources.

Which type of application have multiple stores flux NgRx Redux RxJS?

Redux is an application state manager for JavaScript applications, and keeps with the core principles of the Flux-architecture by having a unidirectional data flow in your application. Where Flux applications traditionally have multiple stores, Redux applications have only one global, read-only application state.


1 Answers

There are a lot of ways to do it. Below will be only my option based on my experience.

First thing to note - forFeature doesn't create an independent store context. It simply connects new reducers and effects on a later stage after a call of forRoot and these effects and reducers will be getting all actions from the whole application, so if you send updateMyLazyFeature(123) in one module - all modules that connected their reducers via forFeature will get this action and reduce it, and it's very easy to get data collisions, when you think that only your module will be updated but in reality it affects other parts of the application too.

When you want to split your store on independent features you need to review how a store feature is used. If the feature is used in more than 1 module, angular will put it in the shared file after build and it doesn't have any benifit compare to forRoot.

if the feature is used in several modules - the best place would be to keep it in forRoot. If you use the feature only in a particular module and it's so tied that there's zero chance to use it anywhere else - then you can put it as a separate store feature.

One more case - if you implement a library with ngrx store, then you need to use forFeature because you can't access forRoot from your lib.

An example, we have a dashboard application and users have to login. It means that we should have access to user's data in several components, in this case the right place would be to put the feature in forRoot.

Apart from that, we have a lazy registration module and a user can use an invitation link to prefill the form. Because the prefilled data won't be used anywhere else and the registration module is seldomly used too, we can implement the feature as forFeature in the registration module. If user isn't going to register during his session - angular won't be going to load the module and the feature at all.

Also in the flux pattern it's important to keep data flat. The main problem flux and ngrx solve is data consistency and the easiest way to achieve it is to keep it flat.

Despite modules are nested like app -> mainboard -> subFeature1 etc, you still can add them to the top level of the store so they'll be stored on the same level as other reducers.

store
    users
    mainboard
    dashboard2
    subFeature1
    subFeature2
    subFeature3

There's no need to make it like

store
    users
    mainboard
        subFeature1
        subFeature2
        subFeature3
    dashboard2
        subFeature1
        subFeature2
        subFeature3

It will bring complexity later when behavior of selectors, reducers and actions isn't so clear and predictable. With the flat structure you can move your feature to another project with ease.

Based on this info I would vote for the flat structure and would use

StoreModule.forFeature('logsControls', logsControls.reducer);

instead of

StoreModule.forFeature('dashboard1', {
  logsControls: logsControls.reducer,
});
StoreModule.forFeature('dashboard2', {
  logsControls: logsControls.reducer,
});

Because in the second case an action will update both dashboard1 and dashboard2 and requires a technique like correlationId to affect only one feature, despite it looks like that dashboard1 and dashboard2 are different features and work independently, that's a wrong guess.

like image 168
satanTime Avatar answered Oct 13 '22 02:10

satanTime