如何在React-Redux史诗中取消HTTP请求

时间:2019-09-26 19:27:45

标签: reactjs react-redux rxjs axios observable

我想取消在redux史诗内部调用的http请求。我的http请求使用axios可以提供取消令牌... 但是,如果我创建了取消令牌,该在哪里使用它?

我使用rxjs / from将我的http请求变成一个可观察的对象,并且使用rxjs中的takeUntil取消订阅该http请求...但这是否真的“取消”了我的http请求?如何确保http请求实际上已取消?我不必使用取消令牌吗?

const loadApplicationNotesEpic: Epic<Action, Action, RootState> = action$ =>
  action$.pipe(
    filter(isActionOf(actions.getApplicationNotes)),
    map(action => action.payload),
    switchMap(applicationId => {
       // create cancel token here?: 
       // const cancelToken = axios.CancelToken;
       // where to use cancelToken?
      return from(axios.get(apiUrl(`/${applicationId}/notes`))).pipe(
        takeUntil(filterAction(action$, actions.getApplicationNotesCancel)),
        map(notes => actions.getApplicationNotesSuccess(notes, applicationId)),
        catchError(error => {
          console.error(error);
          return of(actions.getApplicationNotesError(error));
        }),
      );
    }),
  );

1 个答案:

答案 0 :(得分:0)

这是我认为您可能正在寻找的示例。我对 axios 不熟悉。我只是从他们的网站上取了取消示例。

我还用switchMap替换了mergeMap,因为我认为如果发出了另一项操作

..
    filter(isActionOf(actions.getApplicationNotes)),
    map(action => action.payload),
..

然后它将取消对 switchMap 返回的先前可观察到的订阅,而不必取消对axios.get

的调用
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

const loadApplicationNotesEpic: Epic<Action, Action, RootState> = action$ =>
  action$.pipe(
    filter(isActionOf(actions.getApplicationNotes)),
    map(action => action.payload),
    mergeMap(applicationId => {
      // create cancel token here?:
      // const cancelToken = axios.CancelToken;
      // where to use cancelToken?

      const promise$ = from(
        axios.get(
          apiUrl(`/${applicationId}/notes`, { cancelToken: source.token })
        )
      ).pipe(
        catchError(error => {
          console.error(error);
          return of(actions.getApplicationNotesError(error));
        })
      );

      const cancelled$ = filterAction(
        action$,
        actions.getApplicationNotesCancel
      ).pipe(mapTo("cancelled"));

      return race(promise$, cancelled$).pipe(
        mergeMap(winner => {
          if (winner === "cancelled") {
            return of(EMPTY).pipe(
                     tap(() => source.cancel('Operation canceled by the user.')),
                     ignoreElements())
          }

          return of(winner).pipe(
            map(notes =>
              actions.getApplicationNotesSuccess(notes, applicationId)
            )
          );
        })
      );
    })
  );