Scientyfic World

How to Use Axios in React: GET, POST, Interceptors and Cancelling Requests

To use Axios in React, install it with npm install axios, create a configured instance with axios.create(), and make requests inside useEffect (or a data library) with api.get(), api.post() and...

Share:

Get an AI summary of this article

Axios with React blog feature image

To use Axios in React, install it with npm install axios, create a configured instance with axios.create(), and make requests inside useEffect (or a data library) with api.get(), api.post() and so on. Axios parses JSON automatically into response.data, rejects the promise on 4xx and 5xx errors, supports interceptors for auth tokens, and can be cancelled with an AbortController when a component unmounts.

This guide covers Axios 1.20 (the current version) with React 19: GET, POST, PATCH and DELETE requests, a reusable instance with interceptors, error handling, timeouts, cancellation, and when plain fetch is enough. I ran every example against a local test API, and the outputs shown are real.

What Is Axios?

Axios is a promise-based HTTP client for the browser and Node.js. In the browser it uses XMLHttpRequest under the hood (newer versions can also use the fetch adapter), and in Node.js it uses the http module, so the same code works on both sides. If HTTP methods, headers and status codes are new to you, read what an HTTP request is first.

Axios vs fetch

Every modern browser and Node.js 18+ now include fetch, so Axios is a convenience rather than a necessity. The practical differences:

Axiosfetch
Installnpm install axiosBuilt in
JSON responsesParsed automatically into response.dataCall await res.json()
Sending JSONPass an object; Axios serializes it and sets Content-TypeJSON.stringify and set the header yourself
HTTP errors (404, 500)Rejects the promiseResolves; you must check res.ok
Timeoutstimeout optionAbortSignal.timeout(ms)
InterceptorsBuilt in, for requests and responsesWrite a wrapper function
Base URL and shared defaultsaxios.create()Write a wrapper function
Upload progressonUploadProgressNot supported directly
Bundle sizeAdds a dependency (about 20 KB gzipped when I bundled it with esbuild)Zero

Choose Axios when you want interceptors, shared configuration and automatic error handling across many API calls; plain fetch is fine for a handful of requests. Either way, the React patterns are the same as in my guide to fetching data with React hooks.

Install Axios

npm install axios

Commit your lockfile and install with npm ci in CI; see the security note at the end of this post for why.

Create an Axios Instance

Instead of calling axios.get with full URLs everywhere, create one instance with your base URL, timeout and headers, and add interceptors to it:

import axios from 'axios';

// One configured instance for your whole app
export const api = axios.create({
  baseURL: 'http://localhost:3000',
  timeout: 1000,                                  // fail requests that take longer than 1 s
  headers: { Accept: 'application/json' },
});

// Request interceptor: attach the auth token to every request
api.interceptors.request.use((config) => {
  const token = getToken();
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

// Response interceptor: one place to react to errors such as an expired session
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) console.log('  [interceptor] 401 received: redirect to login here');
    return Promise.reject(error);
  },
);

let token = null;
export const setToken = (t) => { token = t; };
const getToken = () => token;

The request interceptor adds the token to every request, so components never handle it. The response interceptor gives you one place to react to an expired session, for example by refreshing the token or sending the user to the login page.

GET, POST, PATCH and DELETE Requests

// GET with query parameters (Axios builds ?q=hello for you)
const { data: found, status } = await api.get('/posts', { params: { q: 'hello' } });
// GET 200 [ { id: 1, title: 'Hello HTTP' } ]

// POST JSON
const created = await api.post('/posts', { title: 'Sent with Axios' });
// POST 201 { id: 2, title: 'Sent with Axios' }

// PATCH (partial update) and DELETE
const patched = await api.patch(`/posts/${created.data.id}`, { title: 'Edited' });
// PATCH 200 { id: 2, title: 'Edited' }
await api.delete(`/posts/${created.data.id}`);
// DELETE 204

// Several requests in parallel
const [all, filtered] = await Promise.all([
  api.get('/posts'),
  api.get('/posts', { params: { q: 'hello' } }),
]);

The response object has data (the parsed body), status, statusText, headers and config. Use put to replace a whole resource, and pass a FormData object to post for file uploads.

Using Axios in a React Component

Make requests in an effect, track loading and error state, and cancel the request in the cleanup function so a slow, stale response can never overwrite a newer one:

import { useEffect, useState } from 'react';
import axios from 'axios';

const api = axios.create({ baseURL: 'http://localhost:3001/api' });

export default function User({ userId }) {
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true);
    setError(null);

    api.get(`/users/${userId}`, { signal: controller.signal })
      .then((res) => setUser(res.data))                 // res.data is already parsed JSON
      .catch((err) => {
        if (axios.isCancel(err)) return;                // we cancelled it; ignore
        setError(err.response ? `HTTP ${err.response.status}` : err.message);
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoading(false);
      });

    return () => controller.abort();                    // cancel if userId changes or we unmount
  }, [userId]);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Something went wrong: {error}</p>;
  return <p>{user.name}</p>;
}

I tested this component in headless Brave against an API where user 1 responds in 800 ms and user 2 in 100 ms. After switching from user 2 to 1 and straight back to 2, it showed the correct “Alan Turing”, and the browser logged the cancelled request for user 1 as net::ERR_ABORTED. For a user that doesn’t exist it showed “Something went wrong: HTTP 404”.

For larger apps, pair Axios with TanStack Query: use your Axios instance inside the query function and pass the signal TanStack Query provides, and you get caching and retries on top. For sharing fetched data across components, see global state with React Redux.

Handling Errors

Axios rejects for three different reasons, and it helps to handle them separately:

try {
  await api.get('/nope');
} catch (err) {
  if (axios.isCancel(err)) {
    // you cancelled it
  } else if (err.response) {
    // the server answered with 4xx/5xx
    console.log(err.response.status, err.response.data);   // 404 { error: 'Not found' }
  } else if (err.request) {
    // no response: network error, CORS failure or timeout
    console.log(err.code, err.message);
  } else {
    // something went wrong setting up the request
  }
}

Use axios.isAxiosError(err) to check that an error came from Axios (it returned true for the 404 in my test). To treat some statuses as success, set validateStatus, for example validateStatus: (s) => s < 500.

Timeouts and Cancelling Requests

// Timeout: the instance above has timeout: 1000
try {
  await api.get('/slow');                     // server takes 2 s
} catch (err) {
  console.log(err.code, err.message);         // ECONNABORTED timeout of 1000ms exceeded
}

// Cancel with AbortController
const controller = new AbortController();
const pending = api.get('/slow', { signal: controller.signal, timeout: 5000 });
controller.abort();
try {
  await pending;
} catch (err) {
  console.log(axios.isCancel(err), err.name, err.code);   // true CanceledError ERR_CANCELED
}

The old CancelToken API is deprecated; use AbortController, which is also what fetch uses.

Security Note: Keep Axios Up to Date and Pinned

On 31 March 2026, attackers took over an Axios maintainer’s npm account and published two malicious versions, 1.14.1 and 0.30.4, which installed a remote access trojan through a fake dependency. They were online for about three hours before being removed (Tenable’s FAQ has the details). If either version was ever installed on a machine or CI runner, treat it as compromised and rotate its credentials. To reduce the risk from any package:

  • Commit package-lock.json and use npm ci, so builds install exactly the versions you reviewed.
  • Update dependencies deliberately (for example with Dependabot or Renovate pull requests), not with blind npm update in CI.
  • Consider npm config set ignore-scripts true for CI installs that don’t need install scripts, since that attack ran through an install script.
  • Check npm audit and your registry’s security advisories regularly.

Conclusion

Axios makes HTTP requests in React a little shorter and more consistent: one configured instance, automatic JSON handling, errors that actually throw, interceptors for tokens and a timeout option. Use it inside effects with an AbortController cleanup (or inside TanStack Query), handle the three kinds of errors separately, and keep your dependency versions pinned. If you only need a couple of simple requests, the built-in fetch does the job without a dependency.

FAQs

How do I use Axios in React?

Install it with npm install axios, create an instance with axios.create({ baseURL }), and call api.get or api.post inside useEffect or a data library. Store response.data in state, handle errors in catch, and cancel with AbortController in the effect cleanup.

Is Axios better than fetch?

Not better, just more convenient. Axios parses JSON automatically, throws on HTTP errors, and has interceptors, timeouts and shared configuration. fetch is built in and adds no bundle size. Both work well with React.

How do I send a POST request with Axios?

Call api.post(url, data) with a JavaScript object; Axios serializes it to JSON and sets the Content-Type header. The parsed response is in response.data.

How do I add an Authorization header to every Axios request?

Use a request interceptor on your instance: api.interceptors.request.use(config => { config.headers.Authorization = `Bearer ${token}`; return config; }).

How do I cancel an Axios request in React?

Create an AbortController in useEffect, pass controller.signal in the request config, and call controller.abort() in the cleanup function. Check axios.isCancel(err) in your catch block to ignore the cancellation.

Does Axios throw an error on 404?

Yes. By default Axios rejects for any status outside 200–299, with the response available on err.response. You can change this with the validateStatus option.

Which Axios versions were compromised?

Versions 1.14.1 and 0.30.4, published on 31 March 2026 and removed within hours. Use a current version, pin it in your lockfile, and treat any machine that installed those versions as compromised.

Snehasish Konger
Developed @scientyficworld.org | Technical writer @Nected | Content Developer
Connect with Snehasish Konger

On This page

Take a Pause with Intervals

A Sunday letter on building, writing, and thinking deeper as a developer — short, honest, and worth your time.

Snehasish Konger profile photo

"Hey there — I'm Snehasish. Hope this post saved you some head-scratching time! I've spent years turning technical chaos into clarity, and I'm here to be your guide through the maze of modern tech. Stick around for more lightbulb moments — we're just getting started."

Related Posts