Add ngrx/effects
Dataflow
Last chapter we suppose that the name in profile is saved in client side only. In a real app, we need update the name in the database.
ngrx/effects handles side effects like updating the database. It is inspired by redux-saga.
Without ngrx/effects, the app updates the database through the Service.
With ngrx/effects, we will go through Effects first to update the database. The Effects will dispatch success or fail Action based on the response got from server. Then Reducer will update the Store state differently depends on success or fail Action it gets.
Optionally, you can use Effects to interact with server directly without Service.
Add ngrx/effects
First install
npm install @ngrx/effects --save
src/app/profile/actions/profile.actions.ts
export class ProfileActions {
static PROFILE_UPDATE_PROFILE = '[Profile] Update Profile';
static PROFILE_UPDATE_PROFILE_SUCCESS = '[Profile] Update Profile Success';
static PROFILE_UPDATE_PROFILE_FAIL = '[Profile] Update Profile Fail';
}
src/app/profile/services/profile.service.ts
import { Observable } from 'rxjs/Observable';
// ...
@Injectable()
export class ProfileService {
// ...
updateProfile(name: string): Observable<string> {
this.currentUser.name = name;
// fake API, here we return an Observable name back directly
return Observable.of(name);
}
}
src/app/profile/effects/profile.effects.ts
import { Injectable } from '@angular/core';
import { Effect, Actions, toPayload } from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { ProfileActions } from '../actions/profile.actions';
import { ProfileService } from '../services/profile.service';
@Injectable()
export class ProfileEffects {
constructor(
private actions$: Actions,
private profileService: ProfileService
) {}
@Effect() updateProfile$ = this.actions$
.ofType(ProfileActions.PROFILE_UPDATE_PROFILE)
.map<Action, string>(toPayload)
.switchMap(name => this.profileService.updateProfile(name)
.map(name => ({ type: ProfileActions.PROFILE_UPDATE_PROFILE_SUCCESS, payload: name }))
.catch(error => Observable.of({ type: ProfileActions.PROFILE_UPDATE_PROFILE_FAIL, payload: error }))
);
}
Remember the RxJS operators we imported in last chapter? Here we are using them map
, switchMap
, catch
, and of
.
src/app/profile/reducers/profile.reducer.ts
Change from
case ProfileActions.PROFILE_UPDATE_PROFILE
to
case ProfileActions.PROFILE_UPDATE_PROFILE_SUCCESS
Because in this case we only want to update the name in the store state when it successfully updates the value in the database.
src/app/app.module.ts
// ...
import { EffectsModule } from '@ngrx/effects';
import { ProfileEffects } from './profile/effects/profile.effects';
@NgModule({
imports: [
EffectsModule.run(ProfileEffects),
// ...
Run the live example for this part.