Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate AbortController with Axios and React?

The Abortcontroller signal is not working for me with Axios in React.

I wanted to replace CancelToken (as it's deprecated) with the AbortController, but it is not working, respectively the requests are not being canceled.

  let testController: AbortController;

  function loadTest() {
    testController = new AbortController();

    TestAPI.getTest(testController.signal)
      .then((e) => {
        console.log(e.data);
      })
      .catch((e) => {
        console.error(e);
      });
  }

Also in the UseEffect Cleanup I do this (here it should cancel) and also the signal's state is set to aborted, but still the request is not canceled:

  useEffect(() => () => {
    if (testController) testController.abort();
    // console.log(testController.signal.aborted) => **true**
  }, []);

Here is my API, where I pass the AbortSignal to the request:

  getTest(signal?: AbortSignal): Promise<AxiosResponse<Test[]>> {
    return axios.get(`${URI}/test`, { signal });
  },

When using Axios.CancelToken.source was working fine, but now with the AbortController, the request is never canceled.

Using: "axios": "^0.26.0",

Did someone manage to integrate the AbortController with React and Axios? Or does the AbortController only work with fetch?

like image 368
bbrinck Avatar asked Nov 21 '25 00:11

bbrinck


2 Answers

According to the docs axios supports the AbortController of the fetch API.

Cancellation

Axios supports AbortController to abort requests in fetch API way:

const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// cancel the request
controller.abort()

It's not clear exactly where testController is declared:

let testController: AbortController;

but I suspect it's in the body of the function component and redeclared on a subsequent render cycle.

I suggest using a React ref to store an AbortController, and reference this ref value around your app. This is so the component holds on to a stable reference of the controller from render cycle to render cycle, to be referenced in any useEffect hook cleanup function to cancel in-flight requests if/when the component unmounts.

const abortControllerRef = useRef<AbortController>(new AbortController());

function loadTest() {
  TestAPI.getTest(abortControllerRef.current.signal)
    .then((e) => {
      console.log(e.data);
    })
    .catch((e) => {
      console.error(e);
    });
}

useEffect(() => {
  const controller = abortControllerRef.current;
  return () => {
    controller.abort();
  };
}, []);
like image 78
Drew Reese Avatar answered Nov 22 '25 16:11

Drew Reese


I would recommend to read this post.

In a nutshell you would like to use useEffect to create controller, and, what is more important, to use return statement to abort the controller.

useEffect(() => {
 const controller = new AbortController();
 const signal = controller.signal;
 getData(signal)

 //cleanup function
 return () => {controller.abort();};
}, [fetchClick]);

getData function can then be your axios call in the form:

const getData = async (signal) =>{
 const res = await axios.get(url, {signal: signal}).then(...)
}
like image 34
Alex S. Avatar answered Nov 22 '25 16:11

Alex S.