I am building a React/Redux app using the redux-thunk middleware to create and handle Ajax requests. I have a particular thunk that is fired pretty often, and I would like to cancel any previously started Ajax requests before firing a new one. Is this possible?
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.
To ignore actions in redux, you should take a look at redux-ignore. It was recommended by Dam Abramov himself.
Writing middleware for Redux is a powerful tool; Redux Thunk is one of the most widely-used middleware for async actions. Thunk is also a default async middleware for Redux Toolkit and RTK Query. If you want a simple API integration for your Redux apps, RTK Query is a highly recommended option.
The benefit of Redux-Saga in comparison to Redux-Thunk is that you can more easily test your asynchronous data flow. Redux-Thunk, however, is great for small projects and for developers who just entered into the React ecosystem. The thunks' logic is all contained inside of the function.
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
If you're using jquery ajax, you can make your action creator return the promise, it will be returned by the dispatch function, then it'll be possible to abort it. Here is an example :
function doSomething() {
return (dispatch) => {
return $.ajax(...).done(...).fail(...);
}
}
componentDidMount(){
this.previousPromise = this.props.dispatch(doSomething());
}
somefnct() {
this.previousPromise.abort();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With