DEV Community

Cover image for useAxios - React custom http client
Nelson Odo
Nelson Odo

Posted on

useAxios - React custom http client

Often times we are faced with difficulty in tracking the request status while making api calls on our react app. Request status here could be the data response, loading status, error encountered, etc.
The work around is usually to create individual useState to manage all the status that we want (like error, data, etc).

This hook is built on top of javascript axios package

First, let’s create the useAxios custom hooks

//useAxios.js

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

const useAxios = props => {
  const [axiosData, setAxiosData] = useState({
    url: null,
    method: "GET",
    body: null,
    headers: null
  });
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [status, setStatus] = useState(null);

  const sourceToken = axios.CancelToken.source();
  const fetchApi = async () => {
    setLoading(true);
    setData(null);
    setError(null);
    setStatus(null);
    try {
      const data = axiosData?.body ? { data: axiosData?.body } : {};
      const headers = axiosData?.headers ? { headers: axiosData?.headers } : {};
      const response = await axiosClient({
        url: axiosData.url,
        method: axiosData.method ?? "GET",
        cancelToken: sourceToken.token,
        ...data,
        ...headers,
      });
      setLoading(false);
      setStatus(response?.status);
      setData(response?.data);
      if (props.onSuccess) props.onSuccess(response?.data);
    } catch (error) {
      const errorMsg = error?.message;
      setLoading(false);
      setError(String(errorMsg));
      setStatus(error?.response?.status);
      if (props.onError) props.onError(errorMsg);
    }
  };

  useEffect(() => {
    if (axiosData.url != null) {
      fetchApi();
    }
    // abort the fetch if screen is dead/inactive
    return () => sourceToken.cancel();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [axiosData]);

  // return [setPostData, data, error, loading, status];
  return { axios: setAxiosData, data, error, loading, status };
};

export default useAxios;
Enter fullscreen mode Exit fullscreen mode

Initialize request with useAxios

To initialize your request

//index.js

import useAxios from "customHooks/useAxios";
const { axios, data, error, loading, status } = useAxios();
Enter fullscreen mode Exit fullscreen mode

axios: custum axios function to make the api request
data: reponse data from the endpoint
error: contains error message if an error occures
status: returns status code of the request

To trigger the api request, for instance when a button is clicked

const onClick = ()=>{
  axios({
      url: "https://example.com"
    });
}
Enter fullscreen mode Exit fullscreen mode

This makes a get request to https://example.com
The axios function can accept multiple parameters like method, body, and headers

What about POST/PATCH/DELETE requests

To make a request with a custom methods, you could do

const onClick = ()=>{
    const data = {
      name:"Sample name",
      category:"sampleCat",
    }
    axios({
      url: "https://example.com",
      method:"POST",
      body:data,
      headers:{...}
    });
}
Enter fullscreen mode Exit fullscreen mode

You can also also listen for success or error response while initializing the useAxios. Here is how you can do this,

 const { axios, data, error, loading, status } = useAxios({
    onSuccess: (data) => {
      console.log(data);
    },
    onError: (error) => {
      console.log(error);
    }
  });
Enter fullscreen mode Exit fullscreen mode

onSuccess is fired when the data is returned from the endpoint
onError is fired when an error occurs.

You can as well enhance the useAxios hook to include base url, token, etc...

Thanks for reading!

Top comments (0)