Оператор Rxjs from () не отправляет данные - PullRequest
0 голосов
/ 24 мая 2019

У меня есть простое приложение на Angular / rxjs / Ngrx, которое запрашивает список фильмов по умолчанию из API.

component.ts

export class MoviesComponent implements OnInit {
  private movies$: Observable<{}> = 
  this.store.select(fromRoot.getMoviesState);
  private films = [];

  constructor(public store: Store<fromRoot.State>) {}

  ngOnInit() {
    this.store.dispatch(new MoviesApi.RequestMovies());
    this.movies$.subscribe(film => this.films.push(film));
    console.log(this.films)
  }

effects.ts

  @Effect()
  requestMovies$: Observable<MoviesApi.MoviesApiAction> = this.actions$
    .pipe(
      ofType(MoviesApi.REQUEST_MOVIES),
      switchMap(actions => this.MoviesApiServ.getDefaultMoviesList()
        .pipe(
          mergeMap(movies => of(new MoviesApi.RecieveMovies(movies))),
          catchError(err => {
            console.log('err', err);
            return of(new MoviesApi.RequestFailed(err));
          })
        )
      )
    );

service.ts

export class MoviesApiService {
  private moviesList = [];

  constructor(private http: HttpClient) { }


  public getDefaultMoviesList(): Observable<{}> {
    DEFAULT_MOVIES.map(movie => this.getMovieByTitle(movie).subscribe(item => this.moviesList.push(item)));
    return from(this.moviesList);
  }

  public getMovieByTitle(movieTitle: string): Observable<{}> {
    return this.http.get<{}>(this.buildRequestUrl(movieTitle))
      .pipe(retry(3), 
        catchError(this.handleError)
      );
  }

}

DEFAULT_MOVIES - это просто массив с заголовками.

Так что мой метод getDefaultMoviesList не отправляет данные. Но если я заменю this.moviesList на жестко заданный массив значений, он будет работать как положено. Что я делаю не так?

UPD Я хотел перебрать список фильмов по умолчанию, затем вызвать для каждого фильма getMovieByTitle , собрать их в массив и отправить как наблюдаемые. Есть ли лучшее решение?

Ответы [ 2 ]

0 голосов
/ 24 мая 2019

1) Возможно, вам следует переместить эту строку в конструктор служб, в противном случае вы будете выдвигать второй массив фильмов по умолчанию каждый раз, когда вы getDefaultMoviesList:

DEFAULT_MOVIES.map(movie => this.getMovieByTitle(movie).subscribe(item => this.moviesList.push(item)));

2) На самом деле вы должны merge выводить каждый http.get:

  public getDefaultMoviesList(): Observable<{}> {
    return merge(DEFAULT_MOVIES.map(movie => this.http.get<{}>(this.buildRequestUrl(movieTitle))
      .pipe(retry(3), 
        catchError(this.handleError)
      )))
  }

3) На самом деле вы должны сделать это только один раз и сохранить его в BehaviorSubject, чтобы не делать новый HTTP-запрос для каждого getDefaultMoviesList

private movies$: BehaviorSubject<any> = new BehaviorSubject<any>();

public getMovies$() {
  return this.movies$.mergeMap(movies => {
    if (movies) return of(movies);
    return merge(DEFAULT_MOVIES.map(movie => this.http.get<{}>(this.buildRequestUrl(movieTitle))
      .pipe(retry(3), 
        catchError(this.handleError)
      ))) 
  })
}

4) Ваша реализация вообще не должна работать, так как:

public getDefaultMoviesList(): Observable<{}> {
  DEFAULT_MOVIES.map(movie => this.getMovieByTitle(movie).subscribe(item => 
        this.moviesList.push(item))); // This line will happen after http get completes
  return from(this.moviesList); // This line will happen BEFORE the line above
}

Таким образом, вы всегда будете возвращать Observable пустого массива.

5) Не следует использовать map, если вы не хотите отображать свой массив в другой. Вы должны использовать forEach вместо.

map используется так:

const mappedArray = toMapArray.map(element => someFunction(element));

0 голосов
/ 24 мая 2019

Вы можете попробовать создать наблюдаемое с помощью оператора of.

Пример: of(this.moviesList);

Один интересный факт, который стоит отметить, это то, что Observable.of([]) будет пустым массивом при подпискек этому.Где, когда вы подписываетесь на Observable.from([]), вы не получите никакого значения.

Observable.of, это статический метод для Observable.Он создает Observable для вас, который выдает значения, которые вы указываете в качестве аргумента (ов) сразу один за другим, а затем отправляет полное уведомление.

...