Lazy Loading of Modules with Ngrx store (4th version)(Angular 2)
To accomplish this we need to apply two concepts. Lazy Loading of modules via angular and also lazily create the state in the store once the module is lazily loaded.
I expect to have basic and working knowledge of ngrx store and angular
Big Picture (Architecture and why we need)
Lazy Loading Angular 2
Angular 2 Router provides the feature to Lazy Load the feature modules.
With Lazy loading we get the lower intitial payload and thus improving the start up time. In a big application it is very importand to divide the domains into feature modules and then lazy load those modules if we use those modules.
For example lets say we have a big application and two of the domains are
product
invocing
Then product manager may only access the product part of the application to create and edit the products and invoicing manager only access the invoicing part of the application to generate the invoices for the customers.
Hence it makes sense not to load the invoicing module for the product manager once product manager logs in as he or she may never need it.
NgRx store
NgRx store is the implementation of the redux pattern along with the power of observables.
In simple terms we can think of the store as the simple angular service containing the state wrapped in an observable.
For changing the state just dispatch an action to the store . Reducers in the store create the new state based on the action and its payload.
Components subscribed to the store will get the new state and thus component will render this new state.
Store seperates the state management from your components and services and also promotes the immutability for the state management.

In the above diagram View is the component or the service which is subscribed to the store and render the current state present in the store.
If View needs to be updated (button click or server request) then the View dispatches an action to the store via the dipatcher. Reducers in the store create the new state and pushes this new state to the underlying behavior subject wrapping the state. As the view is subsribed to the store and hence will get the new state and rerender this new state.
Now lets apply above concepts to the application.
Lets take a mailbox like application where once we log in , we see two links
Dashboard
Mailbox

So we design this we will create the two feature modules ie one for the dashboard and one for the mailbox.
by default user will redirect to the dashboard where user can see his own information. Now here to decrease the initial payload we may not load the mailbox module at all and just load the all the js and html for the dashboard initially. Also state for the mailbox will not be created in the store as it is not required yet.
Just have in mind we are trying to accomplish two things
- Lazy loading of mail box module
- Lazily create the state required for mailox
If user decide to check his mailbox then only lazy load mail box module and create the state also in the store.
So in the above picture you can see that only userinfo state is created in the store but not mailbox state.
Both the code and the state related to the mailbox is not loaded or created in the browser memory.
Now once we click the mailmox link

As we click the mailbox link both the code and state gets downloaded and created for the mailbox. We do an ajax request to get the folders for the user. We can see inbox and trash folder.
Lets see the code to set up.
- Main App Module
Above is the main app module.
- RouterModule.forRoot(routes) -to configure the routes for root app
- StoreModule.forRoot(reducers)- to attach the root state in the store
lets put the focus on the routes. Dashboard module is eagerly loaded and thus we import the dashboard module.We redirect to the /dashboard . In Dashboard module we tell to the angular router to render the dashbord component for /dashbord path.
Dashboard component fetches the userinfo from the server. Typically in the ngOnit of dasboard component request is made and on success of it just dispatch an action to the store to update the userInfo. Also in the ngOnit select the userinfo state from store via selectors and just render that state in the component html.
For the maibox route we only specify the string literal specifying the file name as the module is not loaded yet. Once the route is activated angular via webpack will get the module code.
StoreModule forRoot function is called with the reducer containing only the userinfo ie rootReducer. This forRoot function will register its providers and also export all its types.
Just to summarize in the main app module we have two forRoot
one for the router. RouterModule.forRoot(routes)
one for the store. StoreModule.forRoot(reducers)
2. Root Reducer
root reducer only contains the userinfo which is required by the dashboard.
3. Mail-box module
This module is lazily loaded by the Angular router. But how to specify to the store to create the state for the mailbox. hint(StoreModule.forFeature)
lets focus on the StoreModule.forFeature. Here we tell to the store to create the mailbox state and merge this state with the current root state(userInfo). Its similar to the RouterModule.forChild function where store will not register the services to the provider again as it is already done in app module via forRoot.
4. Mail-Box Reducer
This reducer just follow the same concepts. MailBox state stores all the folders present in the mailbox. Ngrx store gives us the nice function to create the selector for the feature module state ie createFeatureSelector.
5. Mail Box component
This component gets the folders from the server and on sucess it dispatches an action to update the store with the folders state. It also selects the mailbox state from the store so that it can render it.
source code can be found here
Summary
- Its important to divide the domains into various feature modules
- Eagerly load only those modules which is required at the start up
- Eagerly create the state in the store only for the eagerly loaded modules
- Create the state in the store as and when the modules are loaded via the StoreModule.forFeature() utility.
