Installing NgRx page
Learn how to add NgRx to an Angular project.
Quick Start: You can checkout this branch to get your codebase ready to work on this section.
Overview
Add NgRx schematics.
Add NgRx dependencies.
Generate Global Store using NgRx schematics.
Generate Login Feature Store using NgRx schematics.
Installing Project Dependencies
We will need access to the Angular cli for this section, so if you haven’t already installed the project’s dependencies (Getting Started), be sure to install them:
npm install
NgRx Dependencies
Since we are going to use multiple NgRx tools, let’s install everything we need:
NgRx Schematics
First, install NgRx schematics, a tool that will allow us to run schematics from the CLI to quickly generate code.
This command will install NgRx schematics and update angular.json
:
npx ng add @ngrx/schematics@14
NgRx Libraries
Next, let’s install the NgRx dependencies.
This command will install the NgRx dependencies and update package.json
and package-lock.json
:
npm install @ngrx/{store,effects,entity,store-devtools}@14 --save
Generating Global Store
We’ll take advantage of NgRx schematics to generate our initial state management files, and register the root of our Global Store within app.module.ts
.
npx ng generate store State --root --state-path store --module app.module.ts
We are now setup to be able to generate NgRx Features.
Generating Login Feature Set
The Login Feature Set in our application will be responsible for holding information about authentication and the authenticated user.
Setup
We’ll take advantage of NgRx schematics to quickly generate a Feature Set:
npx ng generate feature store/login/Login --module app.module.ts --reducers ../../store/index.ts
NgRx schematics will prompt us with a few questions:
Should we generate and wire success and failure actions?
Yes. We will modify the Actions a little bit, but this is enough to get started.What should be the prefix of the action, effect and reducer?
load. The default value. We will change the names for Actions, Effects and Reducers, so don’t worry about the prefix right now.
This command accomplishes the following:
- Creates a
src/app/store/login
directory containinglogin.actions.ts
,login.effects.ts
,login.reducer.ts
, andlogin.selecors.ts
, as well as associated spec files - Updates
app.module.ts
to initialize the Login Feature Store and Feature Effects - Updates
src/app/store/index.ts
to: a. Add Login Feature Reducers map b. Add the Login State type to the GlobalState
interface
Register Root EffectsModule
in AppModule
This project has prettier installed, so you can format files throughout the course. Right now the imports
for AppModule
found at src/app/app.module.ts
has a long imports array. To make this more readable, we will format this file. To do this using vscode, we can open src/app/app.module.ts
then press Shift
+ Option
+ F
for Mac or press Shift
+ Alt
+ F
for Windows:
src/app/app.module.ts
// src/app/app.module.ts
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginModule } from './login/login.module';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import * as fromLogin from './store/login/login.reducer';
import { EffectsModule } from '@ngrx/effects';
import { LoginEffects } from './store/login/login.effects';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
LoginModule,
StoreModule.forRoot(reducers, { metaReducers }),
!environment.production ? StoreDevtoolsModule.instrument() : [],
StoreModule.forFeature(fromLogin.loginFeatureKey, fromLogin.reducer),
EffectsModule.forFeature([LoginEffects]),
],
bootstrap: [AppComponent],
})
export class AppModule {}
Next, we need to manually update our app.module.ts
to register NgRx Global Effects. To accomplish this, we need to add EffectsModuloe.forRoot([])
to our AppModule
imports, as shown below:
src/app/app.module.ts
// src/app/app.module.ts
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginModule } from './login/login.module';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import * as fromLogin from './store/login/login.reducer';
import { EffectsModule } from '@ngrx/effects';
import { LoginEffects } from './store/login/login.effects';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
LoginModule,
StoreModule.forRoot(reducers, { metaReducers }),
EffectsModule.forRoot([]),
!environment.production ? StoreDevtoolsModule.instrument() : [],
StoreModule.forFeature(fromLogin.loginFeatureKey, fromLogin.reducer),
EffectsModule.forFeature([LoginEffects]),
],
bootstrap: [AppComponent],
})
export class AppModule {}
Generate Login Feature
Lastly, we need to update src/app/store/login/login.reducer.ts
to include a LoginPartialState
interface, which is easier to import when:
- Writing tests for
Components
using NgRx Selectors - Writing tests for NgRx Selectors themselves
src/app/store/login/login.reducer.ts
// src/app/store/login/login.reducer.ts
import { Action, createReducer, on } from '@ngrx/store';
import * as LoginActions from './login.actions';
export const loginFeatureKey = 'login';
export interface State {
}
export interface LoginPartialState {
[loginFeatureKey]: State;
}
export const initialState: State = {
};
export const reducer = createReducer(
initialState,
on(LoginActions.loadLogins, state => state),
on(LoginActions.loadLoginsSuccess, (state, action) => state),
on(LoginActions.loadLoginsFailure, (state, action) => state),
);
Wrap-up: By the end of this section, your code should match this branch. You can also compare the code changes for our solution to this section on GitHub or you can use the following command in your terminal:
git diff origin/ngrx-init