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 Overflow
🌐
Js
redux-resource.js.org › recipes › canceling-requests
Canceling Requests | Redux Resource
April 18, 2018 - The xhr library simplifies the creation of XHR objects. Because it returns a native XMLHttpRequest object, canceling requests with xhr is the same as when you use the native XMLHttpRequest constructor. Redux Resource XHR for Redux Resource uses xhr for requests.
🌐
GitHub
github.com › reduxjs › redux-toolkit › issues › 1117
[docs] Provide createAsyncThunk cancellation example for ignoring/cancelling previous fetch requests · Issue #1117 · reduxjs/redux-toolkit
June 1, 2021 - [docs] Provide createAsyncThunk cancellation example for ignoring/cancelling previous fetch requests#1117 ... Thanks for this very useful library, makes working with redux fun. Just some feedback: I had the use case that all but the latest fetch network requests should be aborted (or at least their results ignored).
Author   jnachtigall
Discussions

reactjs - Cancelling previous async action using redux-thunk - Stack Overflow
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 More on stackoverflow.com
🌐 stackoverflow.com
Cancel previous fetch request with redux-thunk
Background of the Problem: I am building a React/Redux app that uses redux-thunk and wretch (a fetch wrapper) to handle asynchronous requests. I have a few search actions that can vary significan... More on stackoverflow.com
🌐 stackoverflow.com
reactjs - How to cancel the RTK-Query requests - Stack Overflow
I am using the RTK query to handle my requests. But I have a problem canceling requests. The scenario is like this, I have a modal to show a form to add a todo but, when users want to close the mod... More on stackoverflow.com
🌐 stackoverflow.com
How to cancel Axios requests in React with redux?
Usually I would call abort() on the action (or thunk if async). It will cancel the action from being passed to the reducer but the HTTP request will still complete. https://redux-toolkit.js.org/api/createAsyncThunk#canceling-while-running EDIT: Though it seems if you're doing a search functionality that you'll want to use a debounce method so you don't send a request on every keydown, but rather after the user stops typing after a certain amount of time. More on reddit.com
🌐 r/webdev
5
2
January 29, 2022
🌐
Frontend Masters
frontendmasters.com › courses › redux-mobx › redux-observable-cancelling-requests
Redux Observable: Cancelling Requests - State Management with Redux & MobX | Frontend Masters
Steve demonstrates how to cancel API requests when a newer request comes through before an older request has finished, preventing flashes of intermediary content within the application. A question is …
Top answer
1 of 3
13

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.

2 of 3
5

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

Top answer
1 of 1
5

I feel pretty silly right now, but this is what it took to get it working.

Solution Steps:

  • Set an AbortController to the initialState of the reducer

reducer.js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
  • Get the AbortController from the state, at the beginning of the fetch action and abort it.
  • Create a new AbortController and pass it into the requestData action.
  • Pass the new AbortController into the signal() param of the wretch call.

actions.js

export function fetchData(params) {
  return (dispatch, getState) => {
    const { controller } = getState().reducer;
    controller.abort();

    const newController = new AbortController();
    dispatch(requestData(newController));
    return api
      .signal(newController)
      .query(params)
      .url('api/data')
      .get()
      .fetchError(err => {
        console.log(err);
        dispatch(apiFail(err.toString()));
      })
      .json(response => dispatch(receiveData(response.items, response.totalItems)))
  }
}

export function requestData(controller) {
  return {
    type: REQUEST_DATA,
    waiting: true,
    controller,
  }
}

In the reducer, for the case of the requestData action, set the new AbortController to the state.

reducer.js

case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };

There's some additional functionality with wretch, an .onAbort() param, that allows you to dispatch other actions when the request is aborted. I haven't coded that out yet, but I figured I'd include the info for anyone else struggling with this.

Find elsewhere
🌐
Js
redux-observable.js.org › docs › recipes › Cancellation.html
Cancellation · redux-observable
This example uses mergeMap (aka flatMap), which means it allows multiple concurrent FETCH_USER requests. If you instead want to cancel any pending request and instead switch to the latest one, you can use the switchMap operator.
🌐
Js
redux-saga.js.org › docs › advanced › TaskCancellation
Task Cancellation | Redux-Saga
import { take, put, call, fork, cancel, cancelled, delay } from 'redux-saga/effects' import { someApi, actions } from 'somewhere' function* bgSync() { try { while (true) { yield put(actions.requestStart()) const result = yield call(someApi) yield put(actions.requestSuccess(result)) yield delay(5000) } } finally { if (yield cancelled()) yield put(actions.requestFailure('Sync cancelled!')) } } function* main() { while ( yield take('START_BACKGROUND_SYNC') ) { // starts the task in the background const bgSyncTask = yield fork(bgSync) // wait for the user stop action yield take('STOP_BACKGROUND_SYNC') // user clicked stop.
🌐
Pluralsight
pluralsight.com › tech insights & how-to guides › tech guides & tutorials
How to Abort a Request While Navigating Away From the Component in React | Pluralsight
December 20, 2019 - export const SEARCH = "SEARCH"; export const CANCEL_SEARCH = "CANCEL_SEARCH"; export const search = term => { return { type: SEARCH, payload: term }; }; export const cancelSearch = () => { return { type: CANCEL_SEARCH }; }; This is going to be an interesting section as we learn how to write our Redux middlewares. A Redux middleware provides an interface through which we can modify and interact with actions that have been dispatched before they hit the Redux store. Redux middlewares can be used to log actions, report errors, making asynchronous requests, etc.
🌐
GitHub
gist.github.com › alexeychikk › 2078366d8fc975922294ae6210648a0f
Cancellation middleware for redux-axios-middleware · GitHub
import { AnyAction, Middleware } from 'redux' import axios, { CancelTokenSource } from 'axios' interface LooseObject { [key: string]: CancelTokenSource[] } const CANCEL_ACTION_REQUESTS = 'CANCEL_ACTION_REQUESTS' const CANCEL_ALL_ACTION_REQUESTS = 'CANCEL_ALL_ACTION_REQUESTS' export const cancelAllActionRequests = (): AnyAction => { return { type: CANCEL_ALL_ACTION_REQUESTS } } export const cancelActionRequest = (actionType: string | string[]): AnyAction => { return { type: CANCEL_ACTION_REQUESTS, actionType } } const cancelRequest = (token: CancelTokenSource) => { token.cancel() } export const
🌐
GitHub
github.com › reduxjs › redux › issues › 1461
Aborting Fetches in Middleware · Issue #1461 · reduxjs/redux
February 29, 2016 - When fetching data asynchronously, use componentWillUnmount to cancel any outstanding requests before the component is unmounted.
Author   switchtrue
🌐
GitHub
github.com › reduxjs › redux-toolkit › issues › 2059
Cancel a query dispatched with RTKQ hook useGetSomethingQuery · Issue #2059 · reduxjs/redux-toolkit
February 21, 2022 - Suppose we have a component which uses a query declared as usual with RTKQ, which depends on an user input: const {data} = useGetSomethingQuery(userInput) The user inputs for instance first and the query fires correctly. Now, while the q...
Author   gygabyte017
🌐
DEV Community
dev.to › pallymore › comment › 19o5n
dispatch can be aborted if you use redux-thunk or redux-saga - only applies t... - DEV Community
it's not limited to fetch or axios - you can use AbortSignal for many things, just be careful it might not throw error automatically when used outside of making requests. ... Sr. FE Dev @ AWS - comments/blogs are my own. ... Sr. FE Dev @ AWS ... axios can either use an AbortController or a CancelToken, check their examples here: axios-http.com/docs/cancellation
🌐
Medium
tech.treebo.com › redux-middlewares-an-approach-to-cancel-redux-actions-7e08b51b83ce
Redux Middlewares — An approach to cancel redux actions | by Sumit Gupta | Treebo Tech Blog
May 7, 2018 - To implement a solution for cancelling of asynchronous redux actions, we first need to understand how an asynchronous redux action works. ... Each asynchronous action has three action types associated with it, which is also synonymous to the three phases of an API request.
🌐
Romandatsiuk
romandatsiuk.com › en › blog › post-cancel-requests-redux-saga
Abort HTTP requests using fetch, React and Redux-Saga
April 6, 2021 - We should use the AbortController object to abort requests. First, create a new AbortController instance (Line 4). Next, pass it as an additional signal parameter to fetch. (Line 10).
🌐
Cef62
cef62.github.io › redux-saga › docs › advanced › TaskCancellation.html
Task cancellation | redux-saga
import { take, put, call, fork, cancel, SagaCancellationException } from 'redux-saga' import actions from 'somewhere' import { someApi, delay } from 'somewhere' function* bgSync() { try { while(true) { yield put(actions.requestStart()) const result = yield call(someApi) yield put(actions.requestSuccess(result)) yield call(delay, 5000) } } catch(error) { if(error instanceof SagaCancellationException) yield put(actions.requestFailure('Sync cancelled!')) } } function* main() { while( yield take(START_BACKGROUND_SYNC) ) { // starts the task in the background const bgSyncTask = yield fork(bgSync) // wait for the user stop action yield take(STOP_BACKGROUND_SYNC) // user clicked stop.
Top answer
1 of 2
1

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.

2 of 2
1

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