Ngrx/rxjs: может ли этот код сначала проверить магазин, а затем улучшить запрос API?

Прежде чем получать новые данные из серверной части, я сначала проверяю, есть ли они уже в магазине, и всегда забочусь о том, чтобы магазин всегда синхронизировался при каждом обновлении.

Для этого мой effect делает следующее:

@Effect()
LoadImage: Observable<LoadImageSuccess> = this.actions$.pipe(
  ofType(AppActionTypes.LOAD_IMAGE),
  withLatestFrom(action => this.store$.select(selectImage, action.payload).pipe(map(result => ({ action, result })))),
  switchMap(observable => observable),
  mergeMap(({ action, result }) =>
    result !== null
      ? of(result).pipe(map(image => new LoadImageSuccess(image)))
      : this.imageApiService.getImage(action.payload).pipe(
          map(image => new LoadImageSuccess(image)),
          catchError(error => EMPTY)
        )
  )
);

Кажется, это работает нормально, но мне интересно, можно ли это сделать лучше:

  1. switchMap(observable => observable), выглядит не очень красиво.
  2. Будет ли состояние в mergeMap лучше обрабатываться через iif?
  3. Когда два компонента отправляют действие LOAD_IMAGE, мой вызов API все еще происходит дважды, потому что первый запрос еще не завершен (и не поместил изображение в хранилище), когда начинается второй запрос. Это не обычное явление с изображениями на моем веб-сайте, но может быть с другими компонентами в будущем, и мне интересно, есть ли способ улучшить это.

Спасибо!

Обратите внимание, если я удалю switchMap(observable => observable),, я получу следующую ошибку:

Объект, который передается mergeMap, если я закомментирую switchMap, имеет тип Store:

Обновлено:

Основываясь на принятом ответе, вот что у меня получилось:

@Effect()
LoadImage: Observable<LoadImageSuccess> = this.actions$.pipe(
  ofType(AppActionTypes.LOAD_IMAGE),
  mergeMap(action =>
    this.store$.select(selectImage, action.payload).pipe(
      mergeMap(imageFromStore =>
        imageFromStore !== null
          ? of(imageFromStore).pipe(map(image => new LoadImageSuccess(image)))
          : this.imageApiService.getImage(action.payload).pipe(
              map(image => new LoadImageSuccess(image)),
              catchError(error => EMPTY)
            )
      )
    )
  )
);

Почему этот switchMap вообще там...?

MikeOne 25.12.2020 14:10

@MikeOne, потому что withLatestFrom над ним возвращает Observable<{LoadImageSuccess, Image}>.

Salvatore Iovene 25.12.2020 14:37

Карта слияния ниже также подпишется на это..?

MikeOne 25.12.2020 14:40

@MikeOne Я отредактировал вопрос, чтобы показать, что произойдет, если я удалю это switchMap.

Salvatore Iovene 25.12.2020 16:19

Да это ожидаемо. Теперь вы получите массив. Удалите деструктуру с помощью «данных» или чего-то еще и утешьте ее.

MikeOne 25.12.2020 17:19

@MikeOne Я обновил вопрос, смотрите в конце. То, что я получаю в mergeMap, относится к типу Store.

Salvatore Iovene 25.12.2020 19:05
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
Promise v/s Observable в Angular
Promise v/s Observable в Angular
В системах Push производитель определяет, когда отправить данные потребителю. Потребитель не знает, когда он получит эти данные.
Подсказка RxJS [filter, skipWhile]
Подсказка RxJS [filter, skipWhile]
Эта подсказка описывает разницу между операторами filter и skipWhile из библиотеки RxJS .
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
0
6
105
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что аргумент, переданный withLatestFrom, является проекционной функцией, поэтому вам приходится прибегать к хаку switchMap.

Если вам нужно проверить на основе текущего действия, я думаю, вам лучше сделать это примерно так:

ofType(...),

// do the check
switchMap(
  action => this.store.select(...)
    .pipe(
      ...,
    // act based on the check's result
    // decided to nest this as a response to question 3
    // since if multiple calls are made at the same time, only the last one will be good to go
    switchMap(({ action, result }) => ...)
  )
),

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