Logo

dev-resources.site

for different kinds of informations.

Preventing memory leak by handling errors and request cancellations separately in Axios

Published at
12/23/2020
Categories
axios
cancel
request
errors
Author
sametweb
Categories
4 categories in total
axios
open
cancel
open
request
open
errors
open
Author
8 person written this
sametweb
open
Preventing memory leak by handling errors and request cancellations separately in Axios

I am currently working on a custom hook in a React application. The hook simply makes an API request to a third party API and fetches some data. My Axios call updates the state of the hook with some data or an error message, based on the response from the API call. I encountered a problem in the implementation and it took me a while to figure out. In this post, I am sharing my solution.

Problem

When making a network request with axios in a React app, you will likely update your state based on the response of the request. The data that comes in the .then() block is usually saved in the state, and the .catch() block usually updates the state with an error message.

const dataFetchingHook = () => {
  const [data, setData] = useState([]);
  const [error, setError] = useState("");

  useEffect(() => {
    axios
      .get("https://someapi.com/data")
      .then((response) => setData(response.data))
      .catch(() => setError("Error fetching data"));
  }, []);
};

return data;

Enter fullscreen mode Exit fullscreen mode

With this approach, it is assumed that every network request will be completed and resulted in either resolve or rejection. However, when the request is canceled halfway, the Promise also rejects and falls into the .catch() block.

To get to my point, now let's set up the network request so that it cancels if the component that uses my dataFetchingHook is unmounted.

useEffect(() => {
  const source = axios.CancelToken.source();

  axios
    .get("https://someapi.com/data", { cancelToken: source.token })
    .then((response) => setData(response.data))
    .catch(() => setError("Error fetching data"));

  return () => {
    source.cancel();
  };
}, []);
Enter fullscreen mode Exit fullscreen mode

The problem resides right here: When the component is unmounted, the network request cancels but canceled network requests fall into the .catch() block of the request, just like errors. However, the .catch() block is trying to update our error state, and React tells us this is a memory leak:

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Enter fullscreen mode Exit fullscreen mode

Solution

axios provides a method to check if a rejection is caused by a network cancellation or not. We simply check inside the .catch() block whether the network request is canceled halfway or completed and rejected by the server.

Let's update the useEffect.

useEffect(() => {
  const source = axios.CancelToken.source();

  axios
    .get("https://someapi.com/data", { cancelToken: source.token })
    .then((response) => setData(response.data))
    .catch((error) => {
      if (axios.isCancel(error)) {
        console.log(error); // Component unmounted, request is cancelled.
      } else {
        setError("Error fetching data");
      }
    });

  return () => {
    source.cancel("Component unmounted, request is cancelled.");
  };
}, []);
Enter fullscreen mode Exit fullscreen mode

Here, I made use of the error argument of the callback inside the .catch() block. axios.isCancel(error) checks if the rejection is caused by a cancellation. Remember, inside useEffect's return statement, we canceled the network request if the component is unmounted.

Now, if there is a network cancellation, in the case of the user clicks somewhere and the data-fetching component is unmounted; the application is not trying to update the state with setError, it logs a different error instead.

Conclusion

Network requests that are made by axios are very easy to cancel. Simply make use of the CancelToken object and cancel the request if the component is unmounted, especially if you are updating your state inside the .catch() block.

request Article's
30 articles in total
Favicon
important status code to be known as API developer
Favicon
HTTP Headers in API
Favicon
Mastering API Request Chaining: Essential Techniques for Developers
Favicon
Increasing API Reliability: Adding Timeouts to Node.js Fetch
Favicon
Python and APIs: how to use Python to connect and interact with APIs
Favicon
Rails Request specs with arbitrary JSON params
Favicon
Criando react hook personalizado para fazer requisições
Favicon
HTTPS: Is it better than HTTP?
Favicon
Python: pytest accessing Flask session and request context variables.
Favicon
[HELP] Spring Boot: field is not set in request
Favicon
I'm Looking for Beta Readers
Favicon
An alternative API mocking library for frontend developers
Favicon
How to send request to join a organization in github
Favicon
Negotiating Languages with Ruby: A Journey through Linguistic Diversity
Favicon
Event-driven architecture over standard client-server aproach
Favicon
Roll your own Request object in Laravel
Favicon
Mezon wrapper for processing HTTP requests
Favicon
Preventing memory leak by handling errors and request cancellations separately in Axios
Favicon
How do you present a PR?
Favicon
How can i access the request object inside a nuxtJS module?
Favicon
React Js Axios Post Request Example Tutorial
Favicon
How to make API request from command line with CURL
Favicon
Request for Node.js has been deprecated
Favicon
NodeJS http homepage 20: request url with link menu
Favicon
Sharing the context with the model in an Express app
Favicon
A simple and useful #react component for helping with asynchronous loading/fetch data
Favicon
Feature request: @mention a user
Favicon
We want Dev.to REST API :)
Favicon
Perform small coding tasks for a reliable source of income?
Favicon
When to request data in SPA

Featured ones: