all, I’m trying to understand what is off about my code involving cancelling an axios post request. I have a form via which a user can make a request for an openai search for movies. While the search is going on, I present the user with a cancel button to abort the search and enter a new search term. When I test, if I abort the request, I still receive the data and it is still processed as if the request were not cancelled.
This is happening in a React component I have devoted to handling the openai request. Per my package.json, I’m using Axios 9.5.0. The first thing I do inside the component is set a state, and then:
const controller = new AbortController();
Here is the handler for when the user submits a search:
const handleSubmit = async () => {
(set some states to set up correct user interface)
try {
const searchResults = await axios.post(
"/api/movies/ai-search",
{
userRequest: request,
},
{ signal: controller.signal }
);
const jsonResults = JSON.parse(searchResults.data);
(do stuff with the returned data)
} catch (err) {
if (axios.isCancel(err)) {
console.log("Request cancelled");
} else {
console.log(err);
}
(set some more states to reflect error message)
);
}
};
And here is the handler for when the user clicks to cancel the current search:
const handleSearchCancel = (e: React.MouseEvent<HTMLButtonElement>) => {
// handler for when user cancels search
console.log("Cancelling the search") // confirm I made it to the handler
controller.abort();
(set a couple of states to update the UI)
};
One problem I thought might be the case is all the state setting: most of them are prop-drilled from the parent component. Might that be causing the problem? Anyway, if I submit a search and then cancel it, I do get the console log that I’m in the right handler. But if I wait a few more moments, the search results do come in and are handled as if the request wasn’t cancelled.
EDIT:
Per Dat’s suggestion, I’ve switched to a useRef
setup:
const abortControllerRef = useRef<AbortController>(new AbortController());
That worked for the first search…but all subsequent searches are immediately cancelled without user input. In researching this, it seems that I need to instantiate a new AbortController for each request. BUT since I am using useRef, I can’t do that within the click handler. Going to try to do it in a custom hook.
2
Answers
OK, with Dat's help we figured it out.
const abortRef = useRef<AbortController>(new AbortController())
and I could reference it in the
cancelSearchHandler
function. BUT...once I did that, then the search is PERMANENTLY aborted. All subsequent searches absent a refresh were automatically cancelled. So...Re-instantiate a new AbortController on search submit. EXCEPT I could not do that inside the submit handler. Cannot use React hooks inside of handlers, they have to live at the top level of the component. So "we" finally got the answer...
Forget the React hooks, use standard JavaScript to instantiate the controller, but do it OUTSIDE the component (brilliant, Dat!). Same module, just outside the component. So:
That was outside the component, which made it equally available to both the submit handler and the cancel handler. Then use it normally.
Can you check your Axios’s version again ? Axios 9.5.0 doesn’t exist.