Type to generate custom UI components with AI

Type to generate UI components from text

OR

Browse thousands of MUI, Tailwind, React components that are fully customizable and responsive.

Explore Components

Axios React: Performing Reliable and Efficient HTTP Requests in React

Web development has evolved beyond merely rendering static content to displaying dynamic interfaces, driven by technological advancements and the high demands for digital products. These demands prompted the creation of tools and techniques that enable more flexible and sophisticated designs, with JavaScript serving as the programming language of the web. JavaScript offers various methods to achieve dynamic and interactive content, including making asynchronous requests to endpoints for fetching dynamic data. Initially, native JavaScript web APIs like XMLHttpRequest and Fetch facilitated this process. But with further technological advancements, Axios emerged to simplify how JavaScript-based applications like React make HTTP requests and handle responses.

Recently, Axios has become a preferred choice for making requests, especially in React applications interacting with server APIs. It also offers additional benefits beyond the functionalities of the native Fetch, details of which we will delve into in a subsequent section. Nevertheless, let us explore what Axios is all about and how to use it in React to perform asynchronous operations efficiently.

But before we delve in, discover our collection of ready-to-use UI components at Purecode AI. Effortlessly generate and integrate our responsive custom components into your project for enhanced user experience.

Understanding Axios in React: An Overview

Axios is a popular JavaScript library for HTTP requests to API endpoints or server resources. Being a cross-platform promise-based HTTP client, it can run in the browser and NodeJS environment. It simplifies executing asynchronous tasks and CRUD (Create, Read, Update, Delete) operations involving server resources. Consider the illustration below:

Developers frequently utilize Axios in a React application because it’s efficient, flexible, and versatile. It extends a React app’s functionalities beyond simple endpoint requests to managing various aspects of API interactions. This task includes submitting form data, transforming requests and responses, and providing protection against Cross-Site Request Forgery (XSRF), etc. Consider the following basic syntax to fetch a server resource:

const axios = require('axios');

// Make a request for a user with a given ID
axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .finally(function () {
    // always executed
  });

Creating A Base Axios instance

Axios provides a way to create a new instance that is specifically configured to your application needs. These configurations include the following:

  • setting default headers,

  • setting base URLs,

  • setting an interceptor, etc.

Creating a base instance ensures the configurations are used every time the React app makes an HTTP request to an API endpoint. Consider the following example code:

import axios from 'axios';
    
const customAxios = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' },
});

In the example above, apart from configuring the baseUrl, the Axios instance is set to have a timeout of 5 seconds for every API call. Additionally, it is noticeable that the headers are configured with a bearer token, providing authentication for the API requests to endpoints with this instance.

Performing API Request with Axios in React

Previously, we discussed how Axios simplifies a React app’s interaction with API endpoints. And the fact that it supports promises ensures efficient handling of asynchronous requests. Two ways exist to create HTTP requests in React, including the following:

Axios provides APIs to facilitate the management of HTTP methods for executing CRUD actions. These include the following:

  • GET request for reading data

  • POST request for creating data

  • PUT request for updating data

  • DELETE request for deleting data

Let’s explore how to perform these HTTP requests in a React application using a public API, the JSON placeholder API.

Making A GET Request

We can employ Axios to initiate a GET request for fetching and reading data from an API endpoint. React offers the useEffect hook, designed to handle data fetching when the component mounts or re-renders by utilizing the dependency array to observe state changes. Consider the following example code:

import React, { StrictMode, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import axios from "axios";

const axiosInstance = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
  timeout: 5000,
});

async function fetchPosts() {
  const posts = new Promise((resolve, reject) => {
    axiosInstance
      .get("/posts?userId=1")
      .then((res) => {
        if (!Array.isArray(res.data)) {
          throw new Error("Unable to fetch posts");
        }

        resolve(res.data);
      })
      .catch((err) => {
        console.log(err);
        reject([]);
      });
  });

  return posts;
}

function App() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    (async function () {
      const postList = await fetchPosts();
      setPosts(postList);
    })();
  }, []);
  return (
    <div>
      <h2>Post list</h2>
      <ul
        style={{
          listStyle: "none",
          paddingLeft: 0,
          display: "grid",
          height: "65vh",
          overflowY: "auto",
          rowGap: "0.5rem",
        }}
      >
        {posts.map((post) => (
          <li
            key={post.id}
            style={{ padding: "0.75rem", border: "1px solid #ccc" }}
          >
            <h4>{post.title}</h4>
            <p>{post.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

const element = (
  <StrictMode>
    <div>
      <App />
    </div>
  </StrictMode>
);

const rootElement = document.getElementById("root");
createRoot(rootElement).render(element);

The illustration below results from the above code example that displays a list of posts from the response data of a resolved promise of an asynchronous request. We ensure an API request is made to fetch data once by providing an empty dependency array to the useEffect hook.

A list of posts from the resolved promise of an asynchronous request

Making A POST Request

Axios also enables a React app to initiate a POST request to create and save data to an endpoint using the post method. This process involves providing a request body containing the data to be saved from a user input. Let’s modify the code example above to create and save a post:

function addPost(post) {
  const newPost = new Promise((resolve, reject) => {
    axiosInstance
      .post("/posts", { ...post, userId: 1 })
      .then((res) => {
        resolve(res.data);
      })
      .catch((err) => {
        console.log(err);
        reject({});
      });
  });

  return newPost;
}

function PostForm({ add }) {
  const [post, setPost] = useState({ title: "", body: "" });
  const changehandler = useCallback((e) => {
    setPost((prevPostVal) => ({
      ...prevPostVal,
      [e.target.name]: e.target.value,
    }));
  }, []);

  const submitHandler = (e) => {
    e.preventDefault();
    add(post);

    setPost({ title: "", body: "" });
  };

  return (
    <form
      onSubmit={submitHandler}
      style={{
        display: "grid",
        rowGap: "0.5rem",
        margin: "0 auto",
        width: "75vw",
      }}
    >
      <input
        type="text"
        value={post.title}
        placeholder="Enter post title"
        name="title"
        style={{ padding: "0.5rem" }}
        onChange={changehandler}
      />
      <textarea
        rows={5}
        value={post.body}
        onChange={changehandler}
        placeholder="Enter post body"
        name="body"
        style={{ padding: "0.5rem" }}
      ></textarea>
      <button style={{ padding: "0.5rem" }} type="submit">
        Create
      </button>
    </form>
  );
}

function App() {
  const [posts, setPosts] = useState([]);
  /*
    Other code logics not relevant to the POST HTTP request
  */

 // Receives the new post, makes a request to add the post and updates the list if successful
  const submitPost = (post) => {
    addPost(post)
      .then((post) => {
        setPosts((currPosts) => [post, ...currPosts]);
      })
      .catch((err) => {
        console.log(err);
      });
  };

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      {/* Contains the form to submit a post */}
      <PostForm add={submitPost} />
      <h2>Post list</h2>
      {/* Post list rendering markup and logic */}
    </div>
  );
}

The code example above contains modifications from the previous implementation to enable the submission of a new post to the endpoint, subsequently updating the UI with the newly added post.

Making A PUT Request

Axios provides a straightforward and efficient way to update a piece of resource information on a server using the PUT method. This approach is particularly relevant when dealing with managing data persistence. Let’s further modify the code above to update a post:

function updatePost(post, id) {
  const updatedPost = new Promise((resolve, reject) => {
    axiosInstance
      .put(`/posts/${id}`, post)
      .then((res) => {
        resolve(res.data);
      })
      .catch((err) => {
        console.log(err);
        reject({});
      });
  });

  return updatedPost;
}

function PostForm({ isEditing, postToEdit, add }) {
  const [post, setPost] = useState({
    title: "",
    body: "",
  });

  /*
    Logic to get data on first render
  */

  const changehandler = useCallback((e) => {
    setPost((prevPostVal) => ({
      ...prevPostVal,
      [e.target.name]: e.target.value,
    }));
  }, []);

  const submitHandler = (e) => {
    e.preventDefault();

    add(post);

    setPost({ title: "", body: "" });
  };

  return (
    <form
      onSubmit={submitHandler}
      style={{
        display: "grid",
        rowGap: "0.5rem",
        margin: "0 auto",
        width: "75vw",
      }}
    >
      <input
        value={post.title}
        placeholder="Enter post title"
        name="title"
        style={{ padding: "0.5rem" }}
        onChange={changehandler}
      />
      <textarea
        rows={5}
        value={post.body}
        onChange={changehandler}
        placeholder="Enter post body"
        name="body"
        style={{ padding: "0.5rem" }}
      ></textarea>
      <button style={{ padding: "0.5rem" }} type="submit">
        {isEditing ? "Update" : "Add"}
      </button>
    </form>
  );
}

function PostList({ posts, editPost }) {
  return (
    <section>
      <section
        style={{
          paddingLeft: 0,
          display: "grid",
          height: "50vh",
          overflowY: "auto",
          rowGap: "0.5rem",
        }}
      >
        {posts.map((post) => (
          <article
            key={post.id}
            style={{ padding: "0.75rem", border: "1px solid #ccc" }}
          >
            <div>
              <h4>{post.title}</h4>
              <p style={{ fontSize: "0.875rem" }}>{post.body}</p>
            </div>
            <div
              style={{
                display: "flex",
                justifyContent: "flex-end",
                alignItems: "center",
                gap: "0.5rem",
              }}
            >
              <button
                onClick={editPost}
                style={{
                  cursor: "pointer",
                  backgroundColor: "transparent",
                  border: "none",
                }}
                id={post.id}
              >
                <FaPen />
              </button>
              <button
                style={{
                  cursor: "pointer",
                  backgroundColor: "transparent",
                  border: "none",
                }}
                id={post.id}
              >
                <FaTimes />
              </button>
            </div>
          </article>
        ))}
      </section>
    </section>
  );
}

function App() {
  const [posts, setPosts] = useState([]);
  const [postToEdit, setPostToEdit] = useState({});
  const [isEditing, setIsEditing] = useState(false);

  /*
    Other code logics not relevant to the PUT HTTP request
  */

  const editHandler = (evt) => {
    const id = evt.currentTarget.id;
    const foundPost = posts.find((post) => post.id == id);

    if (!foundPost) return;
    setPostToEdit(foundPost);

    setIsEditing(true);
  };

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <PostForm
        add={submitPost}
        postToEdit={postToEdit}
        isEditing={isEditing}
      />
      <h2>Post list</h2>
      <PostList posts={posts} editPost={editHandler} />
    </div>
  );
}

Modifications to the previous implementation included a request to update a post using the Axios PUT method, displaying a UI with the updated entry.

Making A Delete Request

Axios provides the delete method to delete existing data from a server resulting in a UI without that data. The code below shows how to use the delete method:

function deletePost(id) {
  const isDeleted = new Promise((resolve, reject) => {
    axiosInstance
      .delete(`/posts/${id}`)
      .then((res) => {
        resolve(true);
      })
      .catch((err) => {
        console.log(err);
        reject(false);
      });
  });

  return isDeleted;
}

function App() {
  const [posts, setPosts] = useState([]);
  const [postToEdit, setPostToEdit] = useState({});
  const [isEditing, setIsEditing] = useState(false);
  
   /*
    Other code logics not relevant to the delete post
  */
  const deleteHandler = (evt) => {
    const id = evt.currentTarget.id;
    deletePost(id).then((deleted) => {
      if (deleted) {
        const filteredPosts = posts.filter((post) => post.id != id);
        setPosts(filteredPosts);
        setIsEditing(false);
      }
    });
  };

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <PostForm
        add={submitPost}
        postToEdit={postToEdit}
        isEditing={isEditing}
      />
      <h2>Post list</h2>
      <PostList
        posts={posts}
        editPost={editHandler}
        deletePost={deleteHandler}
      />
    </div>
  );
}

Putting it all together would result in the following:

import React, { StrictMode, useCallback, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import axios from "axios";
import { FaPen } from "react-icons/fa6";
import { FaTimes } from "react-icons/fa";

const axiosInstance = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
  timeout: 5000,
});

async function fetchPosts() {
  const posts = new Promise((resolve, reject) => {
    axiosInstance
      .get("/posts?userId=1")
      .then((res) => {
        if (!Array.isArray(res.data)) {
          throw new Error("Unable to fetch posts");
        }

        resolve(res.data);
      })
      .catch((err) => {
        console.log(err);
        reject([]);
      });
  });

  return posts;
}

function addPost(post) {
  const newPost = new Promise((resolve, reject) => {
    axiosInstance
      .post("/posts", { ...post, userId: 1 })
      .then((res) => {
        resolve(res.data);
      })
      .catch((err) => {
        console.log(err);
        reject({});
      });
  });

  return newPost;
}

function updatePost(post, id) {
  const updatedPost = new Promise((resolve, reject) => {
    axiosInstance
      .put(`/posts/${id}`, post)
      .then(({data}) => {
        resolve(data);
      })
      .catch((err) => {
        console.log(err);
        reject({});
      });
  });

  return updatedPost;
}

function deletePost(id) {
  const isDeleted = new Promise((resolve, reject) => {
    axiosInstance
      .delete(`/posts/${id}`)
      .then((res) => {
        resolve(true);
      })
      .catch((err) => {
        console.log(err);
        reject(false);
      });
  });

  return isDeleted;
}

function PostForm({ isEditing, postToEdit, add }) {
  const [post, setPost] = useState({
    title: "",
    body: "",
  });

  useEffect(() => {
    if (isEditing) {
      setPost((prevPost) => ({
        ...prevPost,
        title: postToEdit.title,
        body: postToEdit.body,
      }));

      return () => {
        console.log("cleanup", isEditing);
        setPost({ title: "", body: "" });
      };
    }
  }, [isEditing, postToEdit]);

  const changehandler = useCallback((e) => {
    setPost((prevPostVal) => ({
      ...prevPostVal,
      [e.target.name]: e.target.value,
    }));
  }, []);

  const submitHandler = (e) => {
    e.preventDefault();

    add(post);

    setPost({ title: "", body: "" });
  };

  return (
    <form
      onSubmit={submitHandler}
      style={{
        display: "grid",
        rowGap: "0.5rem",
        margin: "0 auto",
        width: "75vw",
      }}
    >
      <input
        type="text"
        value={post.title}
        placeholder="Enter post title"
        name="title"
        style={{ padding: "0.5rem" }}
        onChange={changehandler}
      />
      <textarea
        rows={5}
        value={post.body}
        onChange={changehandler}
        placeholder="Enter post body"
        name="body"
        style={{ padding: "0.5rem" }}
      ></textarea>
      <button style={{ padding: "0.5rem" }} type="submit">
        {isEditing ? "Update" : "Add"}
      </button>
    </form>
  );
}

function PostList({ posts, editPost, deletePost }) {
  return (
    <section>
      <section
        style={{
          paddingLeft: 0,
          display: "grid",
          height: "50vh",
          overflowY: "auto",
          rowGap: "0.5rem",
        }}
      >
        {posts.map((post) => (
          <article
            key={post.id}
            style={{ padding: "0.75rem", border: "1px solid #ccc" }}
          >
            <div>
              <h4>{post.title}</h4>
              <p style={{ fontSize: "0.875rem" }}>{post.body}</p>
            </div>
            <div
              style={{
                display: "flex",
                justifyContent: "flex-end",
                alignItems: "center",
                gap: "0.5rem",
              }}
            >
              <button
                onClick={editPost}
                style={{
                  cursor: "pointer",
                  backgroundColor: "transparent",
                  border: "none",
                }}
                id={post.id}
              >
                <FaPen />
              </button>
              <button
                onClick={deletePost}
                style={{
                  cursor: "pointer",
                  backgroundColor: "transparent",
                  border: "none",
                }}
                id={post.id}
              >
                <FaTimes />
              </button>
            </div>
          </article>
        ))}
      </section>
    </section>
  );
}

function App() {
  const [posts, setPosts] = useState([]);
  const [postToEdit, setPostToEdit] = useState({});
  const [isEditing, setIsEditing] = useState(false);

  useEffect(() => {
    (async function () {
      const postList = await fetchPosts();
      setPosts(postList);
    })();
  }, []);

  const submitPost = async (post) => {
    try {
      let newPosts = {};
      if (isEditing) {
        const updatedPost = await updatePost(post, postToEdit.id);
        newPosts = posts.map((p) => (p.id == postToEdit.id ? updatedPost : p));
        setIsEditing(false);
      } else {
        const newPost = await addPost(post);
        newPosts = [newPost, ...posts];
      }
      setPosts(newPosts);
    } catch (err) {
      console.log(err);
    }
  };

  const editHandler = (evt) => {
    const id = evt.currentTarget.id;
    const foundPost = posts.find((post) => post.id == id);

    if (!foundPost) return;
    setPostToEdit(foundPost);

    setIsEditing(true);
  };

  const deleteHandler = (evt) => {
    const id = evt.currentTarget.id;
    deletePost(id).then((deleted) => {
      if (deleted) {
        const filteredPosts = posts.filter((post) => post.id != id);
        setPosts(filteredPosts);
        setIsEditing(false);
      }
    });
  };

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <PostForm
        add={submitPost}
        postToEdit={postToEdit}
        isEditing={isEditing}
      />
      <h2>Post list</h2>
      <PostList
        posts={posts}
        editPost={editHandler}
        deletePost={deleteHandler}
      />
    </div>
  );
}

const element = (
  <StrictMode>
    <div>
      <App />
    </div>
  </StrictMode>
);

const rootElement = document.getElementById("root");
createRoot(rootElement).render(element);

The illustration above captures the result of performing an HTTP request with Axios. Check out the video tutorial below to learn more about making HTTP requests in React:

Asynchronous Operations With Axios in React

Asynchronous operations are a crucial aspect of functional programming that ensures code execution is not delayed or blocked by a task, such as initiating an HTTP request. This allows for the continual processing of code. The following is a graphical illustration of an asynchronous operation:

We can use Axios with React to achieve asynchronous operations in two ways:

  • Promised-base approach

  • Async/Await method

Promise-based Approach

Axios uses native JavaScript Promises to manage asynchronous operations in a functional and composable way. A Promise is a returned object representing an asynchronous task’s eventual completion or failure. It enables the chaining of a series of handlers that ensures the efficient management of the outcome of asynchronous operations, such as resolving or rejecting a Promise. Consider the following syntax:

import axios from 'axios';

axios.get()
  .then((result) => doSomethingElse(result))
  .then((finalResult) => {
    console.log(`Got the final result: ${finalResult}`);
  })
  .catch(failureCallback);

I’m sure you recognize this syntax because we used it a lot in our previous examples to manage the result of the Promise returned by an HTTP request.

Async/Await method

Async/await provides a simplified and flexible approach for dealing with Promises and handling asynchronous operations. By marking a function with the async keyword, we guarantee it always returns a Promise. In addition, placing the await keyword in front of a Promise makes JavaScript wait until that promise settles and returns its result. Leveraging async/await with Axios in React enables us to avoid unnecessary Promise chaining and write synchronous-looking code while gracefully handling asynchronous operations. The following example modifies the earlier code example to use async/await:

async function fetchPosts() {
  try {
    const { data } = await axiosInstance.get("/posts?userId=1");
    if (!Array.isArray(data)) {
      throw new Error("Unable to fetch posts");
    }

    return data;
  } catch (err) {
    console.log(err);
    return [];
  }
}

async function addPost(post) {
  try {
    const { data } = await axiosInstance.post("/posts", {
      ...post,
      userId: 1,
    });

    return data;
  } catch (err) {
    console.log(err);
    return {};
  }
}

async function updatePost(post, id) {
  try {
    const { data } = await axiosInstance.put(`/posts/${id}`, post);
    return data;
  } catch (err) {
    console.log(err);
    return {};
  }
}

async function deletePost(id) {
  try {
    const res = await axiosInstance.delete(`/posts/${id}`);
    if (!res.status === 200) {
      throw new Error("Unable to delete post due to some error");
    }
    return true;
  } catch (err) {
    console.log(err);
    return false;
  }
}

Differences Between the Promise-based and Async/await Asynchronous Operations

This section offers more insight by exploring the differences between the two asynchronous operations. Let’s delve into some of their differences in the table below:

PromiseAsync/await
It represents an intermediate state of operation guaranteed to be completed at some point in the future.It is a syntactic sugar for working with Promises, providing a more readable and synchronous-like structure to asynchronous code in JavaScript.
Promises use promise chaining to control the flow of execution, which can get complicated and hard to read.It is straightforward. legible and has a simpler syntax.
The promise object provides a catch method for handling errors.It requires a try-and-catch block for error handling.
It has wide browser support.It is supported by most modern browsers.

Best Practices for Utilizing Axios in React

Now that we have established the capabilities of Axios in a React app, let us explore best practices to consider when working with Axios in React. These include the following:

  • Leveraging async/await for asynchronous operations

  • Managing concurrent request

  • Intercepting API request and response

  • Canceling request

  • Managing Axios instance with custom hooks

  • Effective handling of errors

Leveraging async/await for Asynchronous Operations

Leveraging the async/await syntax is crucial for exploiting the full capabilities of performing asynchronous operations with Axios. This approach helps avoid unnecessary Promise chaining while writing efficient and maintainable code for handling HTTP requests in asynchronous operations.

Managing Concurrent Request with Axios in Rreact

Managing concurrent requests involves handling multiple asynchronous operations simultaneously. In native JavaScript, we use the Promise.all() syntax. However, Axios provides the axios.all() to streamline the process of making concurrent requests and manage its response data more efficiently. Consider the following example:

import React, { StrictMode, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import axios from "axios";

async function fetchAlbumDetails() {
  try {
    const albumPromise = axiosInstance.get("/albums/1");
    const albumPhotosPromise = axiosInstance.get("/photos?albumId=1");

    const [albumRes, albumPhotosRes] = await axios.all([
      albumPromise,
      albumPhotosPromise,
    ]);

    return { album: albumRes.data, albumPhotos: albumPhotosRes.data };
  } catch (err) {
    console.log(err);
    return { album: null, albumPhotos: [] };
  }
}

function AlbumPhotos({ photos }) {
  return (
    <section>
      <section
        style={{
          paddingLeft: 0,
          display: "flex",
          flexWrap: "wrap",
          height: "80vh",
          overflowY: "auto",
          gap: "0.5rem",
        }}
      >
        {photos.map((photo) => (
          <article
            key={photo.id}
            style={{
              padding: "0.75rem",
              border: "1px solid #ccc",
              width: "100px",
            }}
          >
            <div>
              <img
                style={{ height: "100px", objectFit: "cover" }}
                src={photo.thumbnailUrl}
                alt={photo.title}
              />
            </div>
            <div>
              <p style={{ fontSize: "1rem", fontWeight: "medium" }}>
                {photo.title.length > 20 ? photo.title.slice(0, 20) + "..." : photo.title}
              </p>
            </div>
          </article>
        ))}
      </section>
    </section>
  );
}

function App() {
  const [album, setAlbum] = useState(null);
  const [photos, setPhotos] = useState([]);

  useEffect(() => {
    (async function () {
      const { album, albumPhotos } = await fetchAlbumDetails();
      setAlbum(album);
      setPhotos(albumPhotos);
    })();
  }, []);

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <h2>{album?.title} albums</h2>
      <AlbumPhotos photos={photos} />
    </div>
  );
}

const element = (
  <StrictMode>
    <div>
      <App />
    </div>
  </StrictMode>
);

const rootElement = document.getElementById("root");
createRoot(rootElement).render(element);

In the example above, Axios handled a concurrent request to fetch data for an album and its photos separately, as illustrated below:

An album and its photos

Intercepting API Request and Response

Axios provides interceptors to intercept API requests and responses. This utility is useful for performing tasks such as adding headers, handling authentication, or modifying request/response data. The following code example shows how to use it:

import axios from "axios";

// Request interceptor
axios.interceptors.request.use(
  (config) => {
    // Modify config before sending the request
    config.headers["Authorization"] = "Bearer YOUR_ACCESS_TOKEN";
    return config;
  },
  (error) => {
    // Handle request error
    return Promise.reject(error);
  }
);
import axios from "axios";

// Response interceptor
axios.interceptors.response.use(
  (response) => {
    // Modify response data before passing it to the calling function
    return response.data;
  },
  (error) => {
    // Handle response error
    return Promise.reject(error);
  }
);

Canceling A Request

By default, Axios automatically handles request cancellation during response-related timeouts, poor network, etc. Nevertheless, Axios provides a way to cancel requests using the following methods:

  • signal

  • cancelToken (deprecated)

Axios uses the AbortController to track ongoing requests and terminate them when some user action is taken. This approach is shown in the following example:

import axios from "axios";

const controller = new AbortController();

const fetchData = async () => {
  try {
    const response = await axios.get("https://api.example.com/data", {
      signal: controller.signal,
    });
    console.log(response.data);
  } catch (error) {
    if (axios.isCancel(error)) {
      console.log("Request canceled:", error.message);
    } else {
      console.error("Error", error.message);
    }
  }
};

// Cancel the request
controller.abort("");

Managing Axios Instance with Custom Hook

In our previous examples, there is the possibility of redundancy in writing the same logic to fetch server resources across different components. Fortunately, React provides a powerful approach to streamlining asynchronous operations. This solution leverages Axios capabilities with React Hooks within dedicated functions known as custom hooks, that can be called and utilized in React functional components. The creation of a custom hook serves to encapsulate and adeptly handle server resource interaction and state changes, effectively mitigating repetition. This method enhances the code modularity and reusability and fosters a more efficient and maintainable development process. The following code example shows how to create a custom hook with Axios:

import React, { useEffect, useState } from "react";
import axios from "axios";

const useAxios = (url, method, payload = null) => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(true);

  const fetchData = async () => {
    axios.defaults.headers.post["Content-Type"] =
      "application/json;charset=utf-8";
    axios.defaults.headers.post["Access-Control-Allow-Origin"] = "*";
    try {
      const res = await axios[method](url, payload);
      setResponse(res.data);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    if (url || method || payload) {
      fetchData();
    }
  }, [url, method, payload]);
  return { response, error, loading };
};

Handling Errors with Axios in React

Effective error handling is one of the vital aspects of working with an API endpoint aside from managing data response. Efficiently handling errors is essential for providing a meaningful error message and user feedback. These errors may occur due to incorrect data, network errors, or requests to a wrong endpoint.

Axios offers powerful error interception capabilities to effectively handle errors. It provides an error object specific to different types of errors. This feature ensures better handling of errors, resulting in enhanced user experience. Below is an example of how Axios handles errors for different situations providing an appropriate error message:

try {
    const res = await axios.get(`https://api.example.com/data`);
  } catch (error) {
    if (error.response) {
      // Request made but the server responded with an error
      console.log(error.response.data);
      console.log(error.response.status);
    } else if (error.request) {
      // Request made but no response is received from the server.
      console.log(error.request);
    } else {
      // Error occurred while setting up the request
      console.log("Error", error.message);
    }
  }

Advantages of Axios in React

Axios offers several benefits in a React application, including:

  • Integration with the React ecosystem: Axios seamlessly integrates well with React and can be utilized for efficiently handling HTTP requests with React Query. This functionality improves performance and user experience.

  • Improves optimization: Axios offers a lightweight and optimized solution to handling HTTP requests and response data. It automatically converts the request body to JSON string, parses response JSON data, sets appropriate headers, etc.

  • Promise-based request: Axios utilizes Promise to provide a clean and legible syntax for handling asynchronous operations.

  • Efficient error handling: Axios offers a streamlined way to handle errors. It automatically detects HTTP errors, ensuring efficient error management and customization of error messages.

  • Extensive browser support: Axios handles browser-specific inconsistency, enabling consistent performance across multiple platforms and versions. This functionality ensures better compatibility and reliable experience for HTTP requests.

  • Robust request and response interception: Axios provides interceptors for globally intercepting and modifying requests and responses. This feature is beneficial for handling authentication, setting headers, or logging.

Final Notes

The ability of Axios to seamlessly integrate well with Frontend libraries, especially React, is evidence of its flexibility. Its popularity is rooted in the diverse range of features Axios offers. These features play a role in improving performance, ensuring consistency, and enhancing user experience. Hence, comprehending its practical applications and proficiently incorporating Axios in your React application guarantees efficient interaction with server resources.

Furthermore, Discover the power of Purecode AI, your go-to platform for ready-to-use customizable UI components. With Purecode AI, you can quickly generate custom UI components, eliminate manual coding, and improve project productivity.

Recommended Reading

If you enjoyed this article on using Axios in React, consider reading the following articles to solidify your React knowledge:

Ofili Chukwuemeka Timothy

Ofili Chukwuemeka Timothy