One approach would be to mark those requests as canceled by giving them random id and checking its status before handling the result.
The way to do this is to assign random id for this call in your first dispatch (inside the thunk) and check it in the reducer before handling the result.
const actionId = Math.random();
dispatch({type: AJAX_LOAD_CONST, id:actionId })
When you want to cancel all of the request use
dispatch({type:HANDLE_AJAX_RESPONSE, id:actionId, results: json })
When you want to handle the results don't forget to send the id that you u
and in the reducer have something like this:
function reducer(state = initialState, action) {
switch (action.type) {
case actions.AJAX_LOAD_CONST:
return Object.assign({}, state, { ajax: state.ajax.concat(action.id) });
case actions.CANCEL_ALL_AJAX:
return Object.assign({}, state, { ajax: [] });
case actions.HANDLE_AJAX_RESPONSE:
if (state.ajax.includes(action.id) {
//return state reduced with action.results here
}
return state;
}
}
If you use XMLHttpRequest or one of it's wrappers (JQuery?) you can also store the requests themselves and call request.abort(). if you use the new fetch api you do not have this luxury as promises lack this behavior.
Answer from mrras on Stack Overflowreactjs - Cancelling previous async action using redux-thunk - Stack Overflow
Cancel previous fetch request with redux-thunk
reactjs - How to cancel the RTK-Query requests - Stack Overflow
How to cancel Axios requests in React with redux?
Videos
One approach would be to mark those requests as canceled by giving them random id and checking its status before handling the result.
The way to do this is to assign random id for this call in your first dispatch (inside the thunk) and check it in the reducer before handling the result.
const actionId = Math.random();
dispatch({type: AJAX_LOAD_CONST, id:actionId })
When you want to cancel all of the request use
dispatch({type:HANDLE_AJAX_RESPONSE, id:actionId, results: json })
When you want to handle the results don't forget to send the id that you u
and in the reducer have something like this:
function reducer(state = initialState, action) {
switch (action.type) {
case actions.AJAX_LOAD_CONST:
return Object.assign({}, state, { ajax: state.ajax.concat(action.id) });
case actions.CANCEL_ALL_AJAX:
return Object.assign({}, state, { ajax: [] });
case actions.HANDLE_AJAX_RESPONSE:
if (state.ajax.includes(action.id) {
//return state reduced with action.results here
}
return state;
}
}
If you use XMLHttpRequest or one of it's wrappers (JQuery?) you can also store the requests themselves and call request.abort(). if you use the new fetch api you do not have this luxury as promises lack this behavior.
I was recently faced with the same problem, in which I had to cancel pending or stale async redux actions. I solved it by creating a cancel redux actions middleware.
In redux we have the concepts of middlewares. So when you are sending the request it will go through a list of middlewares. Once the api responds back its response will pass through a number of middlewares before it reaches redux store and eventually your UI.
Now suppose we have written a cancel middleware. The api request will go through this middleware when it being initiated and the api response will also go through this middleware when the api responds back.
Each api request in redux is associated with an action, each action has a type and payload.
Write a middleware, which whenever an api request is done stores the action type associated. Along with it, it stores a flag which states whether to discard this action. If an action of similar type is fired again, make this flag true which says discard this action. When the api response comes for the previous action since the discard flag for this api request has been set to true, send null as response from the middleware.
Look at this blog for detailed information about this approach.
https://tech.treebo.com/redux-middlewares-an-approach-to-cancel-redux-actions-7e08b51b83ce
There is hardly any value in doing that. If your request is pending, as long as you are not within the first few milliseconds, that request has already been sent to the server and the client is just waiting for the response. The server will keep processing that request even if you cancel it and data on the server is probably already changed. So it usually makes sense to let the request finish and then invalidate all cache data (usually, by refetching) that has potentially been changed by the mutation.
If you cancel the request, invalidation will not happen.
All that said: if you triggered your mutation with myTriggerFunction(), you can do
const request = myTriggerFunction()
// ...
request.abort()
You can use custom hook to wrap mutation:
const { useMyMutation } = dataHandlerApi;
const timeout = 5000;
export const useMyMutationWithTimeout = () => {
const [trigger, data] = useMyMutation();
const triggerWithTimeout = (args) => {
const request = trigger(args);
setTimeout(() => request?.abort(), timeout);
};
return [triggerWithTimeout , data];
};
I am using redux in my React app. I want to implement a live search functionality where action is dispatched every time user types a key and the API is called a side effect. Now I want to automatically cancel the previous requests. How to do that?
So far I tried canceltoken and abort controller. They either do not work or just canceling all the requests. How to correctly identify the multiple requests and cancel the unwanted req?
Title. Let's say i dispatch the action as soon as my component mounts, but then it immediately unmounts. I want the pending request to stop, how can i?
I had a similar problem, I'm using jquery for making ajax request and redux-thunk middleware.
The solution is to make your action creators return the promise, this promise will be returned by the dispatch function, then you'll be able to abort it.
In my action creator I have something like this :
function doSomething() {
return (dispatch) => {
return $.ajax(...).done(...).fail(...);
}
}
Then in my component I have :
componentDidMount(){
this.myPromise = this.props.dispatch(doSomething());
}
somefnct() {
this.myPromise.abort();
}
Also have a look at this comment by Dan Abramov.
I was recently faced with the same problem, in which I had to cancel pending or stale async redux actions. I solved it by creating a cancel redux actions middleware.
In redux we have the concepts of middlewares. So when you are sending the request it will go through a list of middlewares. Once the api responds back its response will pass through a number of middlewares before it reaches redux store and eventually your UI.
Now suppose we have written a cancel middleware. The api request will go through this middleware when it being initiated and the api response will also go through this middleware when the api responds back.
Each api request in redux is associated with an action, each action has a type and payload.
Write a middleware, which whenever an api request is done stores the action type associated. Along with it, it stores a flag which states whether to discard this action. If an action of similar type is fired again, make this flag true which says discard this action. When the api response comes for the previous action since the discard flag for this api request has been set to true, send null as response from the middleware.
Look at this blog for detailed information about this approach. https://tech.treebo.com/redux-middlewares-an-approach-to-cancel-redux-actions-7e08b51b83ce