Как мне получить свои наблюдаемые значения для использования в эффекте NGRX

Честно говоря, я полный нуб в NGRX и имею ограниченный опыт работы с rxjs. Но по сути у меня есть код, похожий на этот:

@Effect()
applyFilters = this.actions$.pipe(
ofType<ApplyFilters>(MarketplaceActions.ApplyFilters),
withLatestFrom(this.marketplaceStore.select(appliedFilters),
  this.marketplaceStore.select(catalogCourses)),
withLatestFrom(([action, filters, courses]) => {
  return [courses,
    this.combineFilters([
      this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.TRAINING_TYPE),
      this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.INDUSTRIES)
      ])
  ];
}),
map(([courses, filters]) => {
  console.log('[applyFilters effect] currently applied filters =>', filters);

  console.log('courseFilters', filters);
  const filteredCourses = (courses as ShareableCourse[]).filter(x => (filters as number[]).includes(+x.id));
  console.log('all', courses);
  console.log('filtered', filteredCourses);

  return new SetCatalogCourses(filteredCourses);
})
);

Вспомогательный метод:

private combineFilters(observables: Observable<number[]>[]): number[] {
if (!observables.some(x => x)) {
  return [];
} else {
  let collection$ = (observables[0]);
  const result: number[] = [];

  for (let i = 0; i < observables.length; i++) {
    if (i >= 1) {
      collection$ = concat(collection$, observables[i]) as Observable<number[]>;
    }
  }

  collection$.subscribe((x: number[]) => x.forEach(y => result.push(y)));
  return result;
}

}

Таким образом, объекты хранилища заполняются, я могу их получить. Я знаю, что наблюдаемые «this.getCourseIdsFromFiltersByFilterType (args)» работают так, как в журнале консоли «фильтров», которые они есть. Но время операции неправильное. Я читал и просто потерялся после того, как попробовал SwitchMap, MergeMap, Fork. Кажется, все выглядит хорошо, но когда я пытаюсь фактически просмотреть коллекции для результата наблюдаемых из службы, они еще не реализованы. Я готов попробовать что угодно, но в простейшей форме проблема такова:

Две наблюдаемые должны вызываться либо в одинаковом порядке, либо довольно близко. Их «результаты» имеют тип number[]. Сложная коллекция классов со свойством 'id', которое должно быть включено в это число []. Это прекрасно работает, когда все результаты не являются асинхронными или компонентными. (Я фиктивил статические значения с помощью переменных, чтобы проверить мой «фильтр», а затем «включает» логику, и это работает). метод возврата, и я просто недостаточно хорош в rxjs, чтобы сформулировать способ сделать его счастливым и обеспечить полную реализацию наблюдаемых для их значений из сервисов для надлежащего использования. Опять же, я вижу, что мой консольный журнал «фильтров» существует. Тем не менее, когда я делаю «длину», она всегда равна нулю, поэтому я знаю, что где-то есть проблема с синхронизацией. Любая помощь горячо приветствуется.


person djangojazz    schedule 03.04.2020    source источник
comment
Является ли getCourseIdsFromFiltersByFilterType методом, который вызывает какую-то, возможно, удаленную службу, которая возвращает Observable<number[]> of courseIds? Если. предыдущее верно, вы хотите объединить результаты двух сделанных вами вызовов?   -  person Picci    schedule 03.04.2020
comment
@Picci Верно. Эти методы получают массив чисел, и я хотел бы объединить и убедиться, что они подписаны на конечный эффект.   -  person djangojazz    schedule 03.04.2020


Ответы (1)


Если я понимаю проблему, вы можете попробовать заменить это

withLatestFrom(([action, filters, courses]) => {
  return [courses,
    this.combineFilters([
      this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.TRAINING_TYPE),
      this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.INDUSTRIES)
      ])
  ];
}),

с чем-то вроде этого

switchMap(([action, filters, courses]) => {
  return forkJoin(
     this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.TRAINING_TYPE),
     this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.INDUSTRIES
  ).pipe(
     map(([trainingFilters, industryFilters]) => {
        return [courses, [...trainingFilters, ...industryFilters]]
     })
}),

Теперь некоторые пояснения.

Когда вы выходите из этого

withLatestFrom(this.marketplaceStore.select(appliedFilters),
  this.marketplaceStore.select(catalogCourses)),

вы передаете следующему оператору этот массив [action, filters, courses].

Следующий оператор должен вызвать некоторые удаленные API и, следовательно, должен создать новый Observable. Таким образом, вы находитесь в ситуации, когда вышестоящий Observable уведомляет о чем-то, что принимается оператором, который создает новый Observable. Аналогичные ситуации возникают, когда необходимо использовать такие операторы, как switchMap, mergeMap (он же flatMap), concatMap и exhastMap. Такие операторы выравнивают внутренний Observable и возвращают его результат. Вот почему я бы использовал один из этих операторов выравнивания. Почему switchMap в вашем случае? Это не совсем короткий рассказ. Может быть, прочитав это, можно пролить свет.

Теперь давайте посмотрим на функцию, переданную switchMap

return forkJoin(
         this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.TRAINING_TYPE),
         this.getCourseIdsFromFiltersByFilterType(filters, CatalogFilterType.INDUSTRIES
      ).pipe(
         map(([trainingFilters, industryFilters]) => {
            return [courses, [...trainingFilters, ...industryFilters]]
         })

Эта функция сначала выполняет 2 удаленных вызова API параллельно через forkJoin, затем берет результат этих 2 вызовов и сопоставляет его с новым массивом, содержащим как courses, так и конкатенацию trainingFilters и industryFilters.

person Picci    schedule 03.04.2020
comment
Круто, работает отлично спасибо. Комбинация SwitchMap с Forkjoin с каналом в карту все еще ускользает от меня, чтобы «получить» ее полностью. То, что вы говорите, имеет смысл, но я больше разработчик С#, и мне просто нужно больше делать это, чтобы полностью понять «когда» использовать различные методы, которые вы описали, такие как switchMap, mergeMap и ExhaustMap. Спасибо! - person djangojazz; 03.04.2020
comment
Вы можете прочитайте это, чтобы увидеть, получите ли вы немного больше ясности в отношении Observables, используемых с удаленными API. - person Picci; 03.04.2020