7

I have multiple component with axios plugin for some get requests. i need some help to cancel all xhr request with axios on component unmount event in react js. but the axios cancel code is not working. its return me cancel() is not a function error.

Code example:-

import axios from 'axios';


var CancelToken = axios.CancelToken;
var cancel;

axios.get('abc/xyz', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

Please help me to implement cancel request in axios.

Thanks.

Sachiv Mehta
  • 71
  • 1
  • 2

4 Answers4

6

It is quite simple. Create the request in componentDidMount and cancel it in componentWillUnmount. Replace the url with an existing JSON file and this snippet will work as expected:

class MyComponent extends Component {
  constructor (props) {
    super(props)

    this.state = {
      data: []
    }
  }

  componentDidMount () {
    this.axiosCancelSource = axios.CancelToken.source()

    axios
      .get('data.json', { cancelToken: this.axiosCancelSource.token })
      .then(response => {
        this.setState({
          data: response.data.posts
        })
      })
      .catch(err => console.log(err))
  }

  componentWillUnmount () {
    this.axiosCancelSource.cancel('Axios request canceled.')
  }

  render () {
    const { data } = this.state

    return (
     <div>
          {data.items.map((item, i) => {
            return <div>{item.name}</div>
          })}
      </div>
    )
  }
}
taseenb
  • 1,378
  • 1
  • 16
  • 31
2

In addition to the @taseenb response, if you use react hooks, here's an example.

Use the useEffect to detect route changes. Then, cancel the requests with the AXIOS CANCEL TOKEN when the route is unmounted. After thtat, generate a new AXIOS CANCEL TOKEN to make a new request. See the Axios Doc to more details (https://github.com/axios/axios).

Route.tsx file

import React, { useEffect } from 'react';
import { Route, RouteProps, useLocation } from 'react-router-dom';
import API from 'src/services/service';

const CustomRoute = (props: RouteProps) => {
  const location = useLocation();

  // Detect Route Change
  useEffect(() => {
    handleRouteChange();

    return () => {
      handleRouteComponentUnmount();
    };
  }, [location?.pathname]);

  function handleRouteChange() {
    // ...
  }

  function handleRouteComponentUnmount() {
    API.finishPendingRequests('RouteChange');
  }

  return <Route {...props} />;
};

export default CustomRoute;

Service.ts file

import { Response } from 'src/models/request';
import axios, {AxiosInstance, AxiosResponse } from 'axios';

const ORIGIN_URL = 'https://myserver.com'
const BASE_URL = ORIGIN_URL + '/api';
let CANCEL_TOKEN_SOURCE = axios.CancelToken.source();
    
function generateNewCancelTokenSource() {
  CANCEL_TOKEN_SOURCE = axios.CancelToken.source();
}

export const axiosInstance: AxiosInstance = axios.create({
  baseURL: BASE_URL,
});

const API = {
  get<DataResponseType = any>(
    endpoint: string,
  ): Promise<AxiosResponse<Response<DataResponseType>>> {
    return axiosInstance.get<Response<DataResponseType>>(endpoint, {
      cancelToken: CANCEL_TOKEN_SOURCE.token,
    });
  },

  // ...Other Functions

  finishPendingRequests(cancellationReason: string) {
    CANCEL_TOKEN_SOURCE.cancel(cancellationReason);
    generateNewCancelTokenSource();
  },
};

export default API;
Lucas Simões
  • 589
  • 5
  • 10
1

You can't cancel a request unless you use RxJS. I suggest you use redux-observable for this purpose. Check this for further information. You have to use takeUntil operator in your Epic and do the cancellation when a cancel action fires. Here's the sample code given by the above resource.

import { ajax } from 'rxjs/observable/dom/ajax';

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      ajax.getJSON(`/api/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );
Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
  • Is this code(redux-observable) woking or relate with promises and component structure ? – Sachiv Mehta Sep 08 '17 at 07:00
  • It uses RxJS `Observables`, which is a stream of events created from your response. Then you have to create a subscription to the Observable to get the results. It also gives nice composing api with lots of operators such as map, flatmap, zip etc. It is a different paradigm than ES6 fetch and promise based approach. This more composable approach. – Ravindra Ranwala Sep 08 '17 at 07:04
  • can you refer me some idea without using redux or server. actually i create an very small level appliaction that have 2 or 3 components that are change with routes. i have to cancel my all api request on unmount() in react js lifecycle. – Sachiv Mehta Sep 08 '17 at 08:59
0

use faxios instead of axios

 let req = faxios()
  .url('abc/xyz')

  .GET

  .then(res => {})
  .catch(err => {});

// canceling...
req.cancel();
challenger
  • 2,184
  • 1
  • 18
  • 25