首页 > 解决方案 > 如何在 react-redux 史诗中取消 http 请求

问题描述

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

我使用 rxjs/from 将我的 http 请求变成了一个 observable,并使用了 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));
        }),
      );
    }),
  );

标签: reactjsreact-reduxrxjsaxiosobservable

解决方案


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

我也替换switchMap为,mergeMap因为我认为如果另一个动作是由

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

然后它将取消对switchMap返回的前一个 observable 的订阅,而不必取消对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)
            )
          );
        })
      );
    })
  );

推荐阅读