Simple Guide to Creating Custom Hooks

Custom hooks are reusable pieces of logic we create for specific functions. They are generally made up of other hooks used inside them. They are named with "use" followed by the functionality of the hook. For example, useFetchData.

According to React's official documentation:
React comes with several built-in Hooks like useState, useContext, and useEffect. Sometimes, you’ll wish that there was a Hook for some more specific purpose: for example, to fetch data, to keep track of whether the user is online, or to connect to a chat room. You might not find these Hooks in React, but you can create your own Hooks for your application’s needs.

How do we create a custom hook?

First, write the code without using a custom hook. You should have a clear idea of the reusable logic you want to create. It could be fetching data from a server, checking if users are online in your app, or a reusable thunk function. Whatever it is, the first step is not to create a hook file and start writing code there. That will only lead to confusion. Make sure your logic works without the hook first, then transfer the code. Let's try to do that.

Here, I am fetching countries from the Restcountries API and displaying them on the page during the initial render using the useEffect hook. I use the Axios library to send a request and am using two pieces of state here, data and error.

This logic of fetching data is quite common, and you may need to do the same thing multiple times. So, it is good practice for creating custom hooks.

// src/App.jsx
import { useState } from "react";
import "./App.css";
import { useEffect } from "react";
import axios from "axios";

export default function App() {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);
  useEffect(() => {
    axios
      .get("https://restcountries.com/v3.1/all")
      .then((res) => setData(res.data))
      .catch((e) => setError(e));
  }, []);
  console.log(data);

  return (
    <div className="container">
      <h1 className="heading">Countries of the world!</h1>
      {error && "Something went wrong in fetching countries data..."}
      <div>
        {data.map((country) => (
          <div key={country.cca3}>
            <div className="country">
              {country.flag}{" "}
              {country.altSpellings.map((name, i) => (
                <p key={name}>
                  {name} {i + 1 >= country.altSpellings.length ? "" : " | "}
                </p>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Creating our fetchData custom hook

First, let's consider a function like useFetch. It should return some data and an error. We can pass a URL to useFetch, and it will process the request and return the data.

// EXAMPLE const [data, error] = useFetch(someURL);

Now that we know what we want, let's separate the relevant data from our App.jsx into a separate function. Create a hooks folder inside your src folder and create a use-fetch.jsx file. Move all the states and logic related to our purpose into this file and return the data we get from the API.

// hooks/use-fetch.jsx
import { useState } from "react";
import axios from "axios";
import { useEffect } from "react";

export default function useFetch(url) {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);
  useEffect(() => {
    axios
      .get(url)
      .then((res) => setData(res.data))
      .catch((e) => setError(e));
  }, [url]);
  return [data, error];
}

We create the useFetch function, which takes a URL parameter. We then initialize the data and error states. Next, we add the useEffect hook and return data and error as an array. After moving the code, update the import statements for useState, axios, and useEffect. Once this is done, your custom hook is ready.

Using Our Custom Hook in App

// src/App.jsx
import "./App.css";
import useFetch from "./hooks/use-fetch";

export default function App() {
  const [data, error] = useFetch("https://restcountries.com/v3.1/all");

  return (
    <div className="container">
      <h1 className="heading">Countries of the world!</h1>
      {error && "Something went wrong in fetching countries data..."}
      <div>
        {data.map((country) => (
          <div key={country.cca3}>
            <div className="country">
              {country.flag}{" "}
              {country.altSpellings.map((name, i) => (
                <p key={name}>
                  {name} {i + 1 >= country.altSpellings.length ? "" : " | "}
                </p>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Now that we have transferred the logic, we will get something like the code snippet above. Here, we call our custom hook with the RestCountries API. This gives us a list of countries. Note that we have not changed anything in our return statement, yet we have reduced a considerable amount of code, thus increasing readability.

Let's run our app and see if everything works.

Thank you for reading this! I hope you now have a better understanding of custom hooks.

0
Subscribe to my newsletter

Read articles from Shiwanshu Shubham directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shiwanshu Shubham
Shiwanshu Shubham

Hey there, I'm Shiwanshu, a passionate frontend developer and designer hailing from India. With proficiency in NextJS, ReactJS, CSS3, HTML5, Figma, UI Design, and Typescript, I've embarked on a journey into the tech space. This blog is a documentation of my progress as I delve deeper into the world of technology.