首页 > 解决方案 > Redux-Observable - Cancel next request if it has same parameters with current one, but let it run when they are different

问题描述

I'm new to reactive programming. Just trying to understand observables and rxjs operators. I have a react-redux application that has a custom middleware to handle cached data and isFetching flags. While it just handles the things I need, it can be complicated for things like cancellation or debouncing. So, I wanted to migrate this application to redux-observable.

I want to not fetch the same movie if it is currently fetching. I just pass a selectIsFetchingMovieById(action.movieId) selector to the custom middleware. If it returns true, it doesn't pass anything to reducers. But when the selector returns false, it fetches the movie, runs through either .then or .catch like any regular promise based fetch data process.

But when I use redux-observable, the isFetching state for the given movieId is already true. Because the reducer already got the ({type: FETCH_MOVIE_REQUEST, movieId: "10" }) action. The selector always returns true.

If I use switchMap, it will cancel the previous request even if it has a different movieId. exhaustMap will not run the next request even if it has a different movieId etc.

Now I have this epic. It works for cachedData situation. If the store already has the movie, it won't continue. But isFetching based on movieId is still a problem.

const fetchMovieEpic = (action$, state$) =>
  action$.pipe(
    ofType(actionTypes.FETCH_MOVIE_REQUEST),
    filter(action => {
      const cachedData = selectors.selectMovie(state$.value, action.movieId);
      return !verifyCachedData(cachedData, action.requiredFields);
    }),
    map(action => action.movieId),
    switchMap(movieId =>
      ajax.getJSON(`${BASE_API_URL}/movie/${movieId}?api_key=${api_key}`).pipe(
        map(response => normalize(response, schemas.movieSchema)),
        map(normalizedData => fetchMovieSuccess(movieId, normalizedData)),
        catchError(() => of(fetchMovieError())),
        takeUntil(
          action$.pipe(
            ofType("FETCH_MOVIE_CANCELLED"),
            filter(action => action.movieId === movieId)
          )
        )
      )
    )
  );

How can I use rxjs operators or any other technique to fullfil this? I don't want to add an extra actionType like FETCH_MOVIE_TOGGLE_LOADING. I already have REQUEST, SUCCESS, ERROR and CANCELLED. And there are a lot of other reducers and epics. So, keeping it simple with operators might be a good option :)

Thanks!

标签: reactjsreduxrxjsreactive-programmingredux-observable

解决方案


根据定义exhaustMap假设可以工作。您可以通过重组流和简化内部流来调试它

exhaustMap(movieId =>ajax.getJSON(`${BASE_API_URL}/movie/${movieId}?api_key=${api_key}`).pipe(catchError(() => of(fetchMovieError()))
),

并查看请求完成后是否会触发后续操作


推荐阅读