reactjs - 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!
解决方案
根据定义exhaustMap
假设可以工作。您可以通过重组流和简化内部流来调试它
exhaustMap(movieId =>ajax.getJSON(`${BASE_API_URL}/movie/${movieId}?api_key=${api_key}`).pipe(catchError(() => of(fetchMovieError()))
),
并查看请求完成后是否会触发后续操作
推荐阅读
- openvpn - OpenVPN 连接时无法访问本地网络
- pandas - 得到错误,一个系列的真值是不明确的。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()
- java - How to display array line by line by pressing Enter
- python-3.x - Python Turtle 或任何其他用于 2D 绘图的库
- flutter-dependencies - Dart 2.10 和 `required` 关键字
- ruby-on-rails - Rails 列错误中的空值(仅在测试中)
- c++ - 这个函数有什么不是线程安全的?
- python - python列表中的内存泄漏问题
- google-cloud-functions - 一段时间后,Google Cloud Functions 速度变慢
- typescript - 如何避免 TypeScript 区分联合中的双重不可为空检查?