Как сделать несколько HTTP-вызовов в Angular6, используя forkJoin и ngrx?
сценарий
В моем приложении angular6 у меня есть три категории: catA, catB, catC. Каждая категория нуждается в данных от 3 API. При нажатии на любую категорию он загружает компонент CategoryDetailsComi, и я отправляю действие (LoadCategoryDetails).
Я реализовал forjoin
выполнять параллельные вызовы API (в обслуживании), а также resolver
чтобы убедиться, что все вызовы выполнены, только тогда компонент должен быть загружен.
проблема
- При нажатии на catA (или перезагрузку страницы),
categoryNames
массив пуст - По нажатию catB (вторая маршрутизация),
CategoryNames
массив показывает список предыдущей категории (catA)
Может быть, один из вызовов API требует времени. и мой распознаватель не настроен должным образом.
Вопрос
Как настроить эффекты и распознаватель??
Как использовать forkjoin для совершения нескольких звонков и отправки данных на компонент?
Код
dipatch action и подписаться на селектор
ngOnInit() { const id = parseInt(this.route.snapshot.paramMap.get('categoryId'), 10); this.store.dispatch(new fromCategory.LoadCategoryDetails(id)); this.store.select(getCategoryDetails) .subscribe((data) => { this.categoryDetails = data[0]; this.journeys = data[1]; this.categories = data[2]; }); // filter only category name // problem this.categories.forEach( category => { this.categoryNames.push(category.name); }); }
эффекты (ищите действие и звоните службе)
@Effect() loadCategoryDetails$ = this.actions$.pipe( ofType<fromCategory.LoadCategoryDetails>(CategoryActionTypes.LoadCategoryDetails), switchMap((action) => { return this.categoryService.getCategoryDetails(action.payload).pipe( map(data => new fromCategory.LoadCategoryDetailsSuccess(data)) ); }) );
сервисная функция, выполняющая несколько вызовов и использующая forkjoin
import { forkJoin } from 'rxjs'; getCategoryDetails(categoryId) { const categoryDetails = this.http.get(url); const journeys = this.http.get(url); const courses = this.http.get(url); return forkJoin([categoryDetails, journeys, courses]); }
распознаватель
export class CategoryDetailsResolver implements Resolve<any> { constructor( private categoryService: CategoryService, private router: Router) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { const categoryId = route.paramMap.get('categoryId'); return this.categoryService.getCategoryDetails(categoryId); } }
Заранее спасибо.
2 ответа
Рефакторинг вашего кода, чтобы НЕ использовать route.snapshot и посмотреть, исправит ли это.
ngOnInit() {
this.route.data.subscribe((data) => {
if(data) {
this.store.dispatch(new fromCategory.LoadCategoryDetails(data.id));
this.store.select(getCategoryDetails)
.subscribe((data) => {
this.categoryDetails = data[0];
this.journeys = data[1];
this.categories = data[2];
this.categories.forEach( category => {
this.categoryNames.push(category.name);
});
});
}
});
}
Ваша реализация forkjoin выглядит хорошо для меня. Но одна проблема, которую я вижу в вашем коде, заключается в том, что вы перебираете категории вне обратного вызова getCategoryDetails. Поскольку он асинхронный, вы всегда должны убедиться, что получаете категории, прежде чем выполнять итерацию. Для этого вы должны переместить код для перебора категорий в функцию успешного обратного вызова.
ngOnInit() {
const id = parseInt(this.route.snapshot.paramMap.get('categoryId'), 10);
this.store.dispatch(new fromCategory.LoadCategoryDetails(id));
this.store.select(getCategoryDetails)
.subscribe((data) => {
this.categoryDetails = data[0];
this.journeys = data[1];
this.categories = data[2];
this.categories.forEach( category => {
this.categoryNames.push(category.name);
});
});
// filter only category name
// problem
}