问题
I have an Observable that makes a request that gives back some information that is different each time. This observable is called by a user clicking a button. I want to prevent the user from clicking this button before the request has returned with information, and once it has returned, allow the user to click for an update once again.
This is the request without stopping the user at any point.
const fetchRepos = () =>
fetch( 'https://api.github.com/search/repositories?q=+language:javascript&sort=updated&order=desc')
.then(response => response.json())
export function fetchReposEpic(action$: any) {
return action$.ofType(FETCH_POPULAR_REPOS_REQUEST)
.switchMap(fetchRepos)
.map(data => ({
type: FETCH_POPULAR_REPOS_SUCCESS,
payload: data.items
}))
}
One solution is to throttle the user for 500 milliseconds after the Observable begins
export function fetchReposEpic(action$: any) {
return action$.ofType(FETCH_POPULAR_REPOS_REQUEST)
.throttleTime(500)
.switchMap(fetchRepos)
.map(data => ({
type: FETCH_POPULAR_REPOS_SUCCESS,
payload: data.items
}))
}
The problem here is I am only estimating how long the request might take, worse still, if the request finishes before this time, the user could click the button and the click would be ignored.
The closest to a solution I have is passing the fetch promise to throttle.
export function fetchReposEpic(action$: any) {
return action$.ofType(FETCH_POPULAR_REPOS_REQUEST)
.throttle(fetchRepos)
.map(data => ({
type: FETCH_POPULAR_REPOS_SUCCESS,
payload: []
}))
}
This will wait until the request has finished and will throttle all other actions until then. The problem is that I do not know how to get the returned value of throttle. All throttle examples I could find also show the returned value of throttle being thrown away.
So to summarize, I want a way to wait until the observable has completed before firing it off again.
回答1:
The solution is for your UI to disable the button based on some state in redux, like isFetchingRepos
and your reducers will flip this to true
when FETCH_POPULAR_REPOS_REQUEST
is received and false
when FETCH_POPULAR_REPOS_SUCCESS
is.
If you later add error handling, make sure you also flip it back to false
when an error action is seen.
The ping/pong example in the docs is actually mostly the same thing https://redux-observable.js.org/docs/basics/Epics.html#a-basic-example. How you structure/store that state in your store is up to you--for more complex cases where ID's are involved and concurrent requests can happen, you'll want to make sure that state is per request (or ID if using switchMap)
来源:https://stackoverflow.com/questions/44667352/rxjs-throttle-fetch-until-request-has-finished