May 27, 2023

5 min read

Understanding the useFetch and useAxios Hook in React.

The useFetch and useAxios hooks are custom hooks that simplify making HTTP requests in React components. It takes away the repetitive tasks involved in making API calls, handling loading states, and error handling thereby reducing the amount of code you need to write, using these custom hooks promotes cleaner and more organized code.

In this article, I will be guiding you to understand and properly use these custom hooks in your next project. Enough talking, right? Let's jump straight into it.

What is a custom hook?

Before you start using the useFetch and useAxios custom hooks, it's important to understand what a custom hook is.

Custom hooks in React are a way to reuse and share logic across different components. They allow you to extract common functionality into a separate function, which can be used by multiple components in your application. A custom hook is simply a JavaScript function whose name starts with "use" (a naming convention in React) and follows the rules of hooks.

API call using Axios

Axios is a popular JavaScript library used for making HTTP requests. API calls can be made using either promises or async/await to handle asynchronous operations. However, in this article, we will be utilizing async/await. we would also be using jsonplaceholder’s posts API.

Let's make a get API call to get the list of posts.

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

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

function App() {
  const getPosts = async () => {
    try {
      const response = await axios.get('/posts');
      console.log(response.data)
    } catch(err) {
        console.log(err)
    }
  }

  useEffect(() => {
    getPosts();
  }, []);

  return (
    <section className='app'>
      Hello World
    </section>
  )
}

export default App

From the above example, we created a baseURL so that we can simply pass the specific path to the Axios method. We utilized Axios.get() to make the API call, and by using async/await within a try-catch block, we can obtain the result or handle any errors that may occur.

Adding states to the API call

Let's add states to save our response and error if any, as well as a loading state for a better user experience and improved control and management of the API call lifecycle.

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

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const getPosts = async () => {
    try {
      const response = await axios.get('/posts');
      setData(response.data);
      setLoading(false);
    } catch(err) {
        setError(err);
        setLoading(false);
    }
  }

  useEffect(() => {
    getPosts();
  }, []);

  return (
    <section className='app'>
      Hello World
    </section>
  )
}

export default App

Creating a useAxios custom hook

I believe by now you already know what a custom hook is since we've discussed it earlier. However, if you want to learn more, you can visit here. Now, let's dive straight into the code snippet.

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

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const useAxios = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const getPosts = async () => {
    try {
      const response = await axios.get('/posts');
      setData(response.data);
      setLoading(false);
    } catch(err) {
        setError(err);
        setLoading(false);
    }
  }

  useEffect(() => {
    getPosts();
  }, []);
    
  // custom hook returns value
  return { data, error, loading };
}

export default useAxios

The code looks similar to the previous example, but now we have created a custom hook named useAxios that returns three values: data, error and loading.

We can make our custom hook dynamic by passing parameters as props to the hook. In our example, we can pass a variable representing the URL path.

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

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const useAxios = (requestParam) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const getPosts = async () => {
    try {
      const response = await axios.get(`/${requestParam}`);
      setData(response.data);
      setLoading(false);
    } catch(err) {
        setError(err);
        setLoading(false);
    }
  }

  useEffect(() => {
    getPosts();
  }, [requestParam]);

  return { data, error, loading };
}

export default useAxios

Creating a useFetch custom hook

Let's repeat what we did previously, but this time we will be making our API call using the Fetch API.

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

const useAxios = (requestParam) => {
  const url = `https://jsonplaceholder.typicode.com/${requestParam}`

  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const getPosts = async () => {
    try {
      const response = await fetch(url)
      const res = await response.json()
      setData(res.data);
      setLoading(false);
    } catch(err) {
        setError(err);
        setLoading(false);
    }
  }

  useEffect(() => {
    getPosts();
  }, [requestParam]);

  return { data, error, loading };
}

export default useAxios

Using the useAxios and useFetch hooks in various component

Now that we have created these hooks, let me show you how you can use them in your different components.

function App() {
  const { data, loading, error } = useAxios("posts");

  return (
    <section className='app'>
      <h1>Posts</h1>
      {loading && <p>loading...</p>}
      {error && <div>{error.message}</div>}
      {data && data.map((posts, index) => <p key={index}>{posts.title}</p>)}
    </section>
  )
}

export default App
//when using the useFetch hook
const { data, loading, error } = useFetch("posts");

In conclusion, the useFetch and useAxios hooks provide convenient and efficient ways to handle API calls in React applications.

I hope you found this article useful and thank you for reading.