Как зациклить эпический звонок

У меня есть следующая эпопея:

import {
  map,
  catchError,
  switchMap,
  takeUntil,
} from 'rxjs/operators';
import {
  FETCH_JOKES,
  jokesReceived,
  FETCH_JOKES_CANCELLED,
  jokesFetchFailed,
} from '../actions/jokes-action';
import { ofType } from 'redux-observable';
import { of, concat } from 'rxjs';
import { ajax } from 'rxjs/ajax';

const getJokes = () =>
  ajax.getJSON('http://api.icndb.com/jokes/random?escape=javascript');

const fetchJokesEpic = action$ => {
  return action$.pipe(
    ofType(FETCH_JOKES),
    switchMap(() =>
      getJokes().pipe(
        map(response => jokesReceived(response)),
        catchError((err, act) => of(jokesFetchFailed(err))),
        takeUntil(action$.pipe(ofType(FETCH_JOKES_CANCELLED)))
      )
    ),
  );
};

export default fetchJokesEpic;

всякий раз, когда отправляется FETCH_JOKES, эта эпопея запускает ajax вызов и в случае успеха отправляет jokesReceived действие или при неудаче jokesFetchFailed.

Я хочу зациклить его, поэтому, если он не будет отменен, конечная точка будет вызываться снова после завершения предыдущего вызова (успех или неудача).

Я подумал, что могу использовать еще один эпик, который отреагирует на действия JOKES_RECEIVED и FETCH_JOKES_ERROR, а затем отправит действие FETCH_JOKES, которое должно снова запустить крик.

import { ofType } from 'redux-observable';
import {
  delay,
  map,
} from 'rxjs/operators';
import {
  JOKES_RECEIVED,
  FETCH_JOKES_CANCELLED,
  FETCH_JOKES_ERROR,
  fetchJokes,
} from '../actions/jokes-action';

const pollJokes = (action$, state$) => {
  return action$.pipe(
    ofType(JOKES_RECEIVED, FETCH_JOKES_ERROR, FETCH_JOKES_CANCELLED),
    delay(2000),
    map(action => {
      console.log('pollJokes.map', action);
      if(action.type === FETCH_JOKES_CANCELLED)
      { 
        console.log("Cancelled")
        return { type: 'POLL_STOPPED' };
      }
      else {
        // loop
        return fetchJokes();
      }
    })
  );
};
export default pollJokes;

Однако это не работает, когда я отправляю действие FETCH_JOKES_CANCELLED. Стек действий выглядит так:

@INIT
FETCH_JOKES
JOKES_RECEIVED
FETCH_JOKES
JOKES_RECEIVED
...
FETCH_JOKES_CANCELLED
FETCH_JOKES
JOKES_RECEIVED
POLL_STOPPED
FETCH_JOKES
JOKES_RECEIVED
...

Я пытался добавить takeUntil в pollJokes эпос, но с такими же плохими результатами

const pollJokes = (action$, state$) => {
  return action$.pipe(
    ofType(JOKES_RECEIVED, FETCH_JOKES_ERROR, FETCH_JOKES_CANCELLED),
    delay(2000),
    map(action => {
      console.log('pollJokes.map', action);
      if(action.type === FETCH_JOKES_CANCELLED)
      { 
        console.log("Cancelled")
        return { type: 'POLL_STOPPED' };
      }
      else {
        // loop
        return fetchJokes();
      }
    }),


    takeUntil(action$.pipe(ofType(FETCH_JOKES_CANCELLED)))


  );
};

С этим приложением эпопея pollJokes перестает работать, как только FETCH_JOKES_CANCELLED отправляется впервые. Теперь я знаю, что эпопея завершилась takeUntil.

Что я могу сделать, чтобы эта "петля" работала? Я мог бы предположить, что реализовать промежуточное ПО, которое будет вызывать fetchJokes при отправке JOKES_RECEIVED, но я искал решение all-rxjs,


person Lukasz 'Severiaan' Grela    schedule 25.09.2018    source источник


Ответы (1)


Вам нужно использовать repeat, чтобы перезапустить эпик, как только он будет отменен takeUntil

const pollJokes = (action$, state$) => {
  return action$.pipe(
    ofType(JOKES_RECEIVED, FETCH_JOKES_ERROR, FETCH_JOKES_CANCELLED),
    delay(2000),
    map(action => {
      console.log('pollJokes.map', action);
      if(action.type === FETCH_JOKES_CANCELLED)
      { 
        console.log("Cancelled")
        return { type: 'POLL_STOPPED' };
      }
      else {
        // loop
        return fetchJokes();
      }
    }),


    takeUntil(action$.pipe(ofType(FETCH_JOKES_CANCELLED))),
    repeat()

  );
};
person Anas    schedule 25.09.2018
comment
Действительно, это помогло, но я уверен, что пробовал это :), есть ли другое решение этой проблемы? - person Lukasz 'Severiaan' Grela; 25.09.2018