Rxjs с избыточным наблюдаемым. Повторить действие

У меня вот такая эпопея:

export const fetchCharacter = (id) =>
  ajax({ url: `https://swapi.co/api/people/${id}` })
    .map(response => fetchCharacterSuccess(response.body))
    .catch(error => Observable.of(fetchCharacterFailure(error.response.body)));

export const startFetchingCharacters = () => ({ type: START_FETCHING_CHARACTERS });

export const fetchUserEpic = (action$, store) =>
  action$.ofType(START_FETCHING_CHARACTERS)
    .delay(3000)
    .mergeMap(
      action => api.fetchCharacter(store.getState().nextCharacterId)
    );

Прямо сейчас он прослушивает только START_FETCHING_CHARACTERS действия и делает один запрос для пользователя.

Теперь я хотел бы продолжать извлекать символы снова и снова (с задержкой) до какого-либо действия по отмене. Как я могу этого добиться?


person Tomasz Mularczyk    schedule 12.11.2017    source источник


Ответы (1)


Сопоставьте наблюдаемую .interval() с выборкой API (или .timer() в зависимости от того, какой именно шаблон задержки вы хотите).

Остановите это с помощью takeUntil().

const delay = 3000
const fetchUserEpic = (action$, store) =>
  action$.ofType(START_FETCHING_CHARACTERS)
    .mergeMap( action => 
      Observable.interval(delay)
        .mergeMap(x => api.fetchCharacter(store.getState().nextCharacterId) )
        .takeUntil(action$.ofType(STOP_FETCHING_CHARACTERS))
    );

Сноска

Строго говоря, внутренний mergeMap() не гарантирует порядок возврата символов. Поскольку api.fetchCharacter() является асинхронным, выборка может возвращаться не по порядку (хотя длинная задержка в 3 с помогает этого избежать).

Использование concatMap() во внутреннем наблюдаемом гарантирует, что выбросы происходят в строгом nextCharacterId() порядке.

Observable.interval(delay)
  .concatMap(x => api.fetchCharacter(store.getState().nextCharacterId) )
person Richard Matsen    schedule 12.11.2017
comment
Я использовал mergeMap вместо flatMap, не уверен, что это разница. Думаю, нет. - person Tomasz Mularczyk; 13.11.2017
comment
Вы правы, они одинаковые. Из исходного кода exports.flatMap = mergeMap_2.mergeMap; - person Richard Matsen; 13.11.2017