Fetching Data in a React Application with Axios

Compared to frameworks like Angular, React is a library that only comes with functionality for state management and view rendering. With fewer tools baked into it, React requires additional, third-party libraries for handling important client-side features, such as routing, internationalization and sending HTTP requests to remote API endpoints. This unopinionated approach leaves the developer the responsibility of choosing these libraries to pair with React.

For example, imagine you had to integrate an HTTP client library into your React application. You could write the HTTP client library from scratch using a low-level, imperative API like XMLHttpRequest. However, depending on the amount of time afforded, you might not have enough time to plan and develop the library to account for every possible use case. Alternatively, you could scour the NPM ecosystem for an open-source package that already supports the features you need along with other features you may need in the future. Just typing "http client" into the NPM search bar returns just under three thousand packages.

Picking a specific package over other similar packages boils down to several factors, such as:

  • Maturity - How old is the package? Is the package used by renowned organizations/companies in their production applications?

  • Community - Is there an active community committed to the continued development of the package?

  • Compatibility with Older Browsers - Does the package support older browsers such as Internet Explorer?

  • Readability and Usability of API - Is the package's API declarative? Is the package's API difficult to grasp?

  • Feature-Support - Is the package rich with features? Does the package contain features that account for uncommon use cases?

  • Size/Performance - Does the package increase the bundle size of the application significantly or insignificantly? Was the package written with tree-shaking in mind? Do the utilities/methods provided by the package consume a lot of memory and/or execute quickly?

  • Error-Handling - Does the package gracefully handle errors? Are error messages helpful in identifying the cause of an issue?

For HTTP client libraries, choosing the Axios library likely makes sense for your React application. It is a popular, promise-based HTTP client with plenty of available configuration options for customizing HTTP requests. Additionally, Axios is isomorphic, which means it can run in both client-side (browser) and server-side (Node.js) environments. With tens of thousands of stargazers on GitHub, Axios's declarative API abstracts away low-level, networking implementation details and allows developers to focus more on the application code.

Below, I'm going to show you how to fetch data in a React application with Axios.

Sending HTTP Requests with XMLHttpRequest and fetch#

If you decide to use a native browser API to send HTTP requests to a server from your application, then there are two widely-used options:

Many old browsers support the XMLHttpRequest object, but its imperative API is outdated by modern standards. To make AJAX calls with XMLHttpRequest, you must:

  1. Instantiate a new XMLHttpRequest object.

  2. Initialize this object with request options such as HTTP method, URL, etc.

  3. Set up an event listener to capture the response once it is sent back by the server and parsed by the browser.

  4. Send the request to the server.

Since it is not promise-based, XMLHttpRequest requires a wrapper function to create a promise-based API that utilizes XMLHttpRequest for the underlying implementation. Below, we wrap XMLHttpRequest within a sendRequest wrapper function that returns a promise capable of sending HTTP requests.

That seems like a lot of code just to send an HTTP request! Fortunately, unlike XMLHttpRequest, the Fetch API is promise-based and boasts a more powerful and flexible feature set. Being promised-based, the Fetch API can make use of ES6 async/await syntax, which cleans up asynchronous code so it reads as synchronous code.

However, the Fetch API has several downsides:

  • Because it is a newer browser API, the Fetch API does not support many older browsers and will require a polyfill to recreate its functionality for these non-supporting browsers. In fact, all versions of Internet Explorer are incompatible with the Fetch API.

  • The Fetch API does not reject on HTTP error statuses (must check response.ok, response.status or response.statusText) and only rejects the promise on a network failure or if the request failed to complete due to a timeout, etc.

  • Compared to XMLHttpRequest, the Fetch API is not as featureful. For example, it lacks the ability to track upload progress.

Sending HTTP Requests with Axios#

With Axios, not only does it provide a promise-based API, but it also supports older browsers and comes with a plethora of useful features:

  • Interceptors for Requests and Responses

  • Automatic Transformation of Request and Response Data

  • Client-Side Protection Against Cross-Site Request Forgery (CSRF)

  • Cancellation of Requests

  • Support for Progress Reports

Under-the-hood, the client-side version of Axios wraps around XMLHttpRequest while the server-side version of Axios wraps around the http module.

To install Axios, run the following command:

To import Axios into your project:

To send HTTP requests with Axios, pass configuration options to the axios promise object:

Or for convenience, use the request method alias .get for GET requests:

Axios automatically provides a request method alias for each HTTP method:

  • GET Request - axios.get(url[, config])

  • POST Request - axios.post(url[, data[, config]])

  • PUT Request - axios.put(url[, data[, config]])

  • PATCH Request - axios.patch(url[, data[, config]])

  • DELETE Request - axios.delete(url[, config])

  • HEAD Request - axios.head(url[, config])

  • OPTIONS Request - axios.options(url[, config])

  • General Request - axios.request(config) (Note: config must specify an HTTP method via the method option.)

To use Axios with the async/await syntax...

If you need to intercept requests before they are sent or responses before they arrive at the .then/.catch blocks, then use interceptors:

Of course, we can cover more features of Axios, but this goes beyond the scope of this blog post. If you want to learn more about Axios and its other features, then check out the Axios documentation.

Data Fetching with Axios and React Hooks#

Typically, data-driven React applications fetch data from a server and display this data to the user via an interactive data visualization. Data should be fetched once the component is mounted to the DOM. This allows us to immediately display a loading message to the user informing them to wait patiently as the data is being retrieved. Once the data is retrieved, then the component replaces the loading message with a data visualization.

Render Loading MessageFetch Data From ServerRender Data Visualization

Therefore, within functional components, data fetching should take place within the useEffect hook, which performs side-effects, such as network requests, similar to the componentDidMount and componentDidUpdate lifecycle methods in class components.

Within the useEffect hook:

  1. Fetch data with Axios.

  2. Once data has been fetched, set the data state variable to this data with the setter function setData.

  3. Regardless of whether or not the data has been fetched or an error has been encountered, set the isLoading state variable to false with the setter function setIsLoading to indicate that the component is no longer loading.

Because this data will only be fetched once, the useEffect hook will be passed an empty dependency array to ensure any state/prop changes don't retrigger the hook and refetch the data again.

Inside of useEffect, we define an async function named fetchData that uses Axios to fetch data from a server located at a particular URL. Once the server returns the response, destructure out the data object from the response object and set the data state variable to this data object. If the request fails or times out, then Axios throws an error, which will be handled by the .catch block. To keep the example short and simple, this .catch block prints the error to the console of the developer tools. After setting the data state variable or handling the error, the isLoading state variable is set to false, which causes the component to render the <svg /> element in place of the <LoadingMessage /> component.

Altogether...

Next Steps#

Try using Axios in your next React project!

Sources#