Как правильно упорядочить и отреагировать на действия в Rx JS и наблюдаемом редуксе? - PullRequest
1 голос
/ 23 марта 2020

Я все еще изучаю веревки, насколько Rx JS идет. Я использую redux-observable в своем проекте, и я действительно наслаждаюсь этим. Однако я чувствую, что мне не удается набрать asp некоторых основных положений, поэтому я хотел бы попросить вас о помощи.

Вот пример кода:

const requestDelete = action$ => {
  const actionSuccess$ = action$.pipe(
    ofType(types.AN_ACTION_THAT_MAY_FAIL_SUCCESS),
    take(1),
    mergeMap(_ => of(actions.deleteSuccess()))
  )

  const actionFailed$ = action$.pipe(
    ofType(types.AN_ACTION_THAT_MAY_FAIL_FAILED),
    take(1),
    mergeMap(_ => of(actions.deleteFailed()))
  )

  return action$.pipe(
    ofType(types.REQUEST_DELETE),
    mergeMap(action =>
      from(SomeService.delete(action.payload)).pipe(
        mergeMap(_ =>
          merge(
            actionSuccess$,
            actionFailed$,
            of(actions.requestAnActionThatMayFail())
          )
        ),
        catchError(err => of(actions.deleteFailed(err)))
      )
    ),
    catchError(err =>
      of({ type: 'CRITICAL_REQUEST_DELETE_ERROR', err })
    )
  )
}

Это поток, который я имею в виду:

  1. Пользователь запрашивает удаление какого-либо ресурса.
  2. A SomeService вызывается для этого.
  3. Если это разрешается, Я хотел бы позвонить requestAnActionThatMayFail. Теперь я хотел бы зависеть от результата этого действия и дождаться его окончания sh.
  4. Если все в порядке, я бы хотел go с actions.deleteSuccess()).
  5. Если это не удается, я хотел бы вызвать ошибки и т. Д. c. с actions.deleteFailed().

Теперь дело в том, что этот код работает , но merge мне плохо. Я подумал, что должен использовать concat и поставить of(actions.requestAnActionThatMayFail()) в качестве первого аргумента. Если я изменю порядок потоков или использую concat, весь epi c не будет работать. Есть идеи, в чем может быть проблема?

1 Ответ

0 голосов
/ 24 марта 2020

Если я изменю порядок потоков

Я подозреваю, что это не сработает, потому что requestAnActionThatMayFail является синхронным действием . Это объясняет, почему, поскольку merge будет подписываться на предоставленные наблюдаемые последовательно , это означает, что если у вас есть

merge(
 actionFailed$,
 of(actions.requestAnActionThatMayFail()),
 actionSuccess$,
)

и requestAnActionThatMayFail успешно, он не будет работать, потому что actionSuccess$ еще не подписан (actionFailed$ подписан). Если requestAnActionThatMayFail был асинхронным , вы не должны сталкиваться с этой проблемой.

или использовать concat

concat, равный merge с concurrent установлен на 1. Хотя merge может иметь несколько активных внутренних наблюдаемых, concat может иметь только одну. Если установлен concurrent, merge будет буферизировать превышенные значения, а когда одна внутренняя наблюдаемая завершит , он примет самое старое буферизованное значение и создаст из него внутреннюю наблюдаемую величину.
Объяснение такой же, как в предыдущем разделе: другие наблюдаемые еще не подписаны .

Итак, вот мой подход:

const requestDelete = action$ => {
  const actionSuccess$ = action$.pipe(
    ofType(types.AN_ACTION_THAT_MAY_FAIL_SUCCESS),
    take(1),
    mergeMap(_ => of(actions.deleteSuccess()))
  )

  const actionFailed$ = action$.pipe(
    ofType(types.AN_ACTION_THAT_MAY_FAIL_FAILED),
    take(1),
    mergeMap(_ => of(actions.deleteFailed()))
  )

  const requestDelete$ = action$.pipe(
    ofType(types.REQUEST_DELETE),
    mergeMap(action =>
      from(SomeService.delete(action.payload)),
      mergeMap(_ => of(actions.requestAnActionThatMayFail())),
      catchError(err => of(actions.deleteFailed(err)))
    ),

    // This seems a little redundant because of the previous `catchError`
    // catchError(err =>
    //   of({ type: 'CRITICAL_REQUEST_DELETE_ERROR', err })
    // )
  )

  // Make sure all the obs. are susbcribed
  return merge(actionSuccess$, actionFailed$, requestDelete$);
}
...