Проверьте наличие элемента в списке загружаемых файлов в ngrx

Я пытаюсь построить последовательность команд RXJS в охране, чтобы достичь этого результата в простом приложении библиотеки (как в книгах):

  • Проверить в магазине
  • Если состояние не загружено, запустите действие
  • После загрузки отфильтруйте данные, чтобы найти один конкретный элемент.
  • Если найдете, разрешите доступ к странице, если нет, отправьте на 404

Некоторое время я боролся, и поиск в Интернете не дает ответа в соответствии с версией 6 Angular или стандартами... Что мне удалось сделать, это создать большую часть, если магазин загружен, прежде чем поразить охранника, но если ему нужно извлечь данные, он зацикливается бесконечно.

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
  return this.store.pipe(
    select(state => state.books),
    tap(state => {
      if (!state.loaded) {
        this.store.dispatch(new BooksActions.Load());
      }
    }),
    filter(state => state.loaded),
    take(1),
    map(state => state.list.find(book => book.id === route.params['id'])),
    map((book) => {
      if(!!book) return true;
      this.router.navigate(['/404']);
      return false;
    })
  );
}

Большое спасибо!

1 ответ

Проблема в этом разделе:

select(state => state.books),
    tap(state => {
      if (!state.loaded) {
        this.store.dispatch(new BooksActions.Load());
      }
    }),   

Как только вы отправите действие Load, скорее всего, ваш редуктор установит загруженное свойство в false, повторно запустив начальный селектор, который снова инициирует отправку действия.

То, как я это вижу, что вам нужно сделать, это:

  1. Проверьте только один раз, если список загружен. Если это не так, отправьте действие. В противном случае NOOP.
  2. Как только предыдущий шаг будет завершен, дождитесь загрузки списка и проверьте один раз на наличие сущности.

Это может быть заархивировано через следующее:

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> 
{
   return concat(this.loadIfRequired(), this.hasBookInStore(route.params['id'])).pipe(skip(1));
}

private loadIfRequired(): Observable<any>
{
   return booksState$.pipe(
    map(state => state.loaded),
    take(1),
    tap(loaded=> {
      if (!loaded) {
        this.store.dispatch(new BooksActions.Load());
      }
    }));
}

private hasBookInStore(id: string): Obsevable<boolean>
{
  return this.booksState$.pipe(
    first(state => state.loaded),
    map(state => state.list.find(book => book.id === id)),
    map((book) => {
     if(!!book) return true;
     this.router.navigate(['/404']);
     return false;
   })
  );
}

private get booksState$(): Observable<BooksState>
{
 return this.store.pipe(
    select(state => state.books));
}

Позвольте мне знать, если это помогает.

Другие вопросы по тегам