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.

results matching ""

    No results matching ""