Refer to ngrx official website: https://ngrx.io/guide/effects#registering-root-effects

Comparison with component-based side effects

In a service-based application, your components interact with data through many different services, which expose data through properties and methods. These services may depend on other services that manage other data sets. Your components use these services to perform tasks, thus giving your components many responsibilities-violating the single responsibility principle of design.

Imagine that your application manages movies. This is a component that retrieves and displays the list of movies.

@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 implementation, responsible for reading movies:

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

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

This small Component does many things as follows:

  • Manage the status of the movie.
  • Use this service to perform side effects and access external APIs to get movies.
  • Change the status of the movie in the component.

The benefits of introducing Store and Effect

When used with Store, Effects will reduce Component's responsibility. In larger applications, this becomes even more important because you have multiple data sources and need multiple services to obtain this data, and services may depend on other services.

Effects handle external data and interactions, allowing your service to achieve less stateful effects, and only perform tasks related to external interactions. Next, refactor the components to put the shared movie data into the Store. Effects handles the acquisition of movie data.

The refactored Component implementation:

@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' });
  }
}

Movies are still acquired through MoviesService, but now the component no longer cares about how to acquire and load movies. It is only responsible for declaring its intention to load the movie, and uses the selector to access the movie list data.

Effects is where the asynchronous activity of fetching the movie takes place. Your component becomes easier to test and is responsible for the data it needs.


注销
1k 声望1.6k 粉丝

invalid