1. 程式人生 > 其它 >如何編寫第一個 ngrx Effect 類

如何編寫第一個 ngrx Effect 類

官網

要將副作用與您的元件隔離,您必須建立一個 Effects 類來偵聽事件並執行任務。

Effect 是具有不同部分的可注入服務類:

  • 一個可注入的 Actions 服務,它提供了在 reduce 最新狀態後排程的所有操作的可觀察流。

如下圖所示:

  • 使用 createEffect 函式將元資料附加到可觀察流。 元資料用於註冊訂閱儲存的流。從 effect 流返回的任何操作都會被分派回 Store。

  • 使用可管道化的 ofType 運算子過濾操作。 ofType 運算子將一種或多種操作型別作為引數來過濾要執行的操作。

如下圖所示:

  • effects 訂閱了 Store observable.

  • 服務被注入到效果中以與外部 API 互動並處理流。

看一個實際的 effects 實現例子:

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { EMPTY } from 'rxjs';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { MoviesService } from './movies.service';

@Injectable()
export class MovieEffects {

  loadMovies$ = createEffect(() => this.actions$.pipe(
    ofType('[Movies Page] Load Movies'),
    mergeMap(() => this.moviesService.getAll()
      .pipe(
        map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
        catchError(() => EMPTY)
      ))
    )
  );

  constructor(
    private actions$: Actions,
    private moviesService: MoviesService
  ) {}
}

loadMovies$ 效果通過 Actions 流監聽所有 dispatch 的 action,但只對使用 ofType 操作符的 [Movies Page] Load Movies 事件感興趣。

我們必須使用 ofType 來過濾事件,應該通過建構函式依賴注入得到的 action 例項是一個單例,預設會捕捉到系統所有 dispatch 的事件。

然後使用 mergeMap 運算子將 action 流展平,並對映到新的可觀察物件中。 MoviesService#getAll() 方法返回一個 observable,該 observable 將電影對映到成功的新 action,如果發生錯誤,當前返回一個空的 observable。

當需要更改狀態時,action 被分派到 Store,在那裡它可以由 reducer 處理。 在處理可觀察流時處理錯誤也很重要,這樣 effect 才能繼續執行。

Registering root effects

編寫 Effects 類後,必須註冊它,以便效果開始執行。 要註冊根級 effects,請將 EffectsModule.forRoot() 方法與您的 effect 陣列新增到您的 AppModule。

下面是 app.module.ts 的例子:

import { EffectsModule } from '@ngrx/effects';
import { MovieEffects } from './effects/movie.effects';

@NgModule({
  imports: [
    EffectsModule.forRoot([MovieEffects])
  ],
})
export class AppModule {}

即使您沒有註冊任何根級效果,也必須將 EffectsModule.forRoot() 方法新增到您的 AppModule 匯入中。

下面的程式碼來自 Spartacus 的 app.module.ts:

效果在 AppModule 載入後立即開始執行,以確保它們儘快偵聽所有相關操作。

Registering feature effects

對於功能模組,通過在 NgModule 的匯入陣列中新增 EffectsModule.forFeature() 方法來註冊你的 effect。

例子:

import { EffectsModule } from '@ngrx/effects';
import { MovieEffects } from './effects/movie.effects';

@NgModule({
  imports: [
    EffectsModule.forFeature([MovieEffects])
  ],
})
export class MovieModule {}

通過 forRoot() 或 forFeature() 多次執行效果類(例如通過不同的延遲載入模組)不會導致效果多次執行。 forRoot() 和 forFeature() 載入的效果之間沒有功能差異; 函式之間的重要區別在於 forRoot() 設定 Effects 所需的 providers 程式。

更多Jerry的原創文章,盡在:"汪子熙":