1. 程式人生 > 其它 >為什麼在大型 Angular 應用裡我們需要使用 ngrx

為什麼在大型 Angular 應用裡我們需要使用 ngrx

參考 ngrx 官網:https://ngrx.io/guide/effects#registering-root-effects

Comparison with component-based side effects

在基於服務的應用程式中,您的元件通過許多不同的服務與資料互動,這些服務通過屬性和方法公開資料。 這些服務可能依賴於管理其他資料集的其他服務。 您的元件使用這些服務來執行任務,從而賦予您的元件許多職責——違反了設計的單一職責原理。

想象一下,您的應用程式管理電影。 這是一個獲取並顯示電影列表的元件。

@Component({
  template: `
    <li *ngFor="let movie of movies">
      {{ movie.name }}
    </li>
  `
})
export class MoviesPageComponent {
  movies: Movie[];
 
  constructor(private movieService: MoviesService) {}
 
  ngOnInit() {
    this.movieService.getAll().subscribe(movies => this.movies = movies);
  }
}

service 實現,負責讀取 movies:

@Injectable({
  providedIn: 'root'
})
export class MoviesService {
  constructor (private http: HttpClient) {}

  getAll() {
    return this.http.get('/movies');
  }
}

這一個小小的 Component,就做了如下許多事情:

  • 管理電影的狀態。
  • 使用該服務執行副作用,訪問外部 API 以獲取電影。
  • 更改元件內電影的狀態。

引入 Store 和 Effect 的好處

與 Store 一起使用時,Effects 會減少 Component 的責任。 在更大的應用程式中,這變得更加重要,因為您有多個數據源,需要多個服務來獲取這些資料,而服務可能依賴於其他服務。

Effects 處理外部資料和互動,允許您的服務實現達到 less stateful 的效果,並且只執行與外部互動相關的任務。 接下來,重構元件以將共享的電影資料放入 Store。 Effects 處理電影資料的獲取。

重構後的 Component 實現:

@Component({
  template: `
    <div *ngFor="let movie of movies$ | async">
      {{ movie.name }}
    </div>
  `
})
export class MoviesPageComponent {
  movies$: Observable<Movie[]> = this.store.select(state => state.movies);
 
  constructor(private store: Store<{ movies: Movie[] }>) {}
 
  ngOnInit() {
    this.store.dispatch({ type: '[Movies Page] Load Movies' });
  }
}

電影仍然通過 MoviesService 獲取,但現在元件不再關心如何獲取和載入電影。 它只負責宣告其載入電影的意圖,並使用 selector 訪問電影列表資料。

Effects 是獲取電影的非同步活動發生的地方。 您的元件變得更容易測試並且對它需要的資料負責。