如何循环史诗般的通话

时间:2018-09-25 16:32:06

标签: reactjs react-redux polling redux-observable rxjs6

我有以下史诗:

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_RECEIVEDFETCH_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,但是我正在寻找一种全rxjs解决方案,

1 个答案:

答案 0 :(得分:2)

一旦史诗被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()

  );
};