Lazily registering state using forFeature()
When an application grows bigger, it is essential that we lazily load the modules and its routes. As the modules are lazily loaded then we will use store.forFeature() to register state. As of now, we are using store.forRoot() to register our todoReducer. Now we don’t want this behavior we only want to register todoReducer when TodoModule is lazily loaded.
store.forFeature doesn’t create an independent store context. It simply connects new reducers and effects on a later stage after a call of store.forRoot and these effects and reducers will be getting all actions from the whole application.
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 one module, Angular will put it in the shared file after build, and it doesn’t have any benefit compare to forRoot.
For example, say we have authState used by multiple modules then the best place to keep would be in store.forRoot. But for todoState which is not used by another other module other than itself we can put it as a separate store feature.
Note: store.forFeature simply appends the latest state to the main app state when the module is loaded.
Making changes in AppModule
@NgModule({
declarations: [AppComponent, VoidComponent],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
StoreModule.forRoot({}),
StoreDevtoolsModule.instrument({maxAge: 25, logOnly: environment.production})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
Lazily loading TodoModule
const routes: Routes = [
{path: '', component: VoidComponent},
{path: 'todo', loadChildren: () => import('../forms/todo/todo.module').then(m => m.TodoModule)}
];
@NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})
export class AppRoutingModule {
}
Configuring TodoModule
const routes: Routes = [
{path: '', component: TodoComponent}
];
@NgModule({
declarations: [TodoComponent],
imports: [
CommonModule,
MatCardModule,
MatButtonModule,
MatInputModule,
ReactiveFormsModule,
RouterModule.forChild(routes),
StoreModule.forFeature(todoFeatureKey, todoReducer)
],
exports: [
RouterModule
],
})
export class TodoModule {
}
VoidComponent
@Component({
selector: 'app-void',
templateUrl: './void.component.html',
})
export class VoidComponent {
}
<!--EMPTY-->
{{< /step >}}
{{< step label=“Adding header” >}}
- Generate HeaderComponent and HeaderModule
ng g c components/header --skip-tests=true
ng g m components/header
- Configure module
@NgModule({
declarations: [HeaderComponent],
imports: [
CommonModule,
MatToolbarModule,
MatButtonModule,
RouterModule
],
exports: [HeaderComponent]
})
export class HeaderModule {
}
- Configure template
<mat-toolbar>
<span>NgRx Workshop</span>
<button mat-button color="primary" routerLink="" routerLinkActive="green" [routerLinkActiveOptions]="{exact: true}">Void</button>
<button mat-button color="primary" routerLink="/todo" routerLinkActive="green">Todo</button>
</mat-toolbar>
- Configure style
// header.component.scss
mat-toolbar {
background: #161616;
}
button {
margin-left: 10px;
}
// styles.scss
.green {
color: #037971 !important;
}
.pink {
color: #e31b6d !important;
}
.red {
color: #ec5453 !important;
}
.coffee {
color: #6f1a07 !important;
}
<!--app.component.html-->
<app-header></app-header>
<router-outlet></router-outlet>