Custom React Hooks: how to build one for your project?

Spread the love

Hello Friends,

In this post we are going to take a look on what is custom react hooks? why we need one? and how to create one when needed? Let us start with understand what is react hook first.

What is React Hook?

The React hooks are simple functions which can help you manange state data without using class component. With Hooks, you can use functional components to manage state and other features by using built-in functions such as useState, useEffect, useContext, and more.

In simple words, Hooks enables developer to write clearn code by providing simpler and concise way for managing state and other features in React applications.

There are multiple react hooks available, why we need to create one?

As you learned about react hooks, these are the functions created to handle generic requirement. for example, useState hook helps you manange state for a functional component. similarly, useEffect hook is used to call side-effects. but, if you have some specific need and you want to export that part of code as a new reusable functions so that other component can also use it, the custom react hooks are way to go. You might also be thinking why not just create a simple function and call it the places you need.

Why to create custom hooks when I can create a function and call it other places?

The main difference between custom hooks and other function is , custom hooks can manage stateful data and encapsulate other react hooks. You can not do this using simple javascript functions.

Here are some key differences between Custom React Hooks and Functions:

  1. State management: Custom React Hooks allow you to manage state using the useState Hook and other built-in Hooks, while functions do not have built-in state management.
  2. Reusability: Both Custom React Hooks and functions are reusable, but Custom React Hooks are specifically designed for encapsulating stateful logic and reusing it across multiple components.
  3. Use cases: Functions are more general purpose and can be used for a wide range of tasks such as calculations, validation, or data formatting. Custom React Hooks are more focused on stateful logic and side effects within a React component.
  4. Naming conventions: Custom React Hooks are named with the “use” prefix, which is a convention that signals to React that the function is a Hook and should be treated as such. Regular functions can be named anything you choose.

Let us start creating a new react application and try to see how to build custom react hooks.

First Let usĀ create new react application and use typescript with it using below command.

npx create-react-app my-app-customhooks-tutorial --template typescript

Open the application in vscode and create folders as per below snap.

Now, If you developed multiple react applications, you might be realized that most of the time, we need to get data from an API and then we keep that that using useState, we also keep another state to manage if we are in a process of fetchinng data or not and probably another one to show if there is some error while fetching data. We are going to build this use-case using React Custom Hooks.

Lets us now install axios using below command which we use mosily for calling API

npm i axios

How I am going to create fake APIs using mocki.io. I am going to pass below json and generate a fake api which will return the same json information when called.

{
  "products": [
    {
      "id": 1,
      "name": "Product 1",
      "price": 9.99
    },
    {
      "id": 2,
      "name": "Product 2",
      "price": 19.99
    },
    {
      "id": 3,
      "name": "Product 3",
      "price": 29.99
    },
    {
      "id": 4,
      "name": "Product 4",
      "price": 39.99
    },
    {
      "id": 5,
      "name": "Product 5",
      "price": 49.99
    }
  ]
}

This is the response from the site. https://mocki.io/v1/bf70f69a-ed5b-495a-aa66-2ebb021dd3ce

Create a new file named “useAPIData.tsx” in hooks folder and add below code in it.

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

function useAPIData(url: string) {
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState<any>(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        setLoading(true);
        const response = await axios.get(url);
        setData(response.data);
        setLoading(false);
      } catch (error: AxiosError | any) {
        setError(error.message);
        setLoading(false);
      }
    }
    fetchData();
  }, [url]);

  return { loading, data, error };
}

export default useAPIData;

This is a custom React hook named useAPIData that fetches data from a specified URL using Axios library and manages the state of loading, data, and errors associated with the API call using useState hook.

When the hook is called with a url parameter, it initializes three state variables with default values:

  • loading variable with false value indicating that data is not being fetched initially.
  • data variable with null value indicating that no data has been fetched yet.
  • error variable with null value indicating that no errors have occurred yet.

The hook returns an object with three properties: loading, data, and error.

  • The loading property indicates whether the API call is in progress or not.
  • The data property contains the response data from the API call if it was successful, otherwise, it remains null.
  • The error property contains the error message if the API call was unsuccessful, otherwise, it remains null.

The hook uses the useEffect hook to execute the fetchData function, which makes an API call using Axios library with the provided URL. If the API call is successful, the response data is set to the data state variable, and loading is set to false. If the API call fails, the error message is set to the error state variable, and loading is set to false.

The catch block in fetchData handles errors that occur during the Axios request. If the error is an Axios error, the error message is taken from the error.message property. Otherwise, the entire error object is returned as the error message.

Finally, the hook is exported to be used in other components.

Note: when creating custom react hook you should be named with “use” prefix.

Create a new file named “product-list.tsx” in components folder and add below code in it.

import useAPIData from "../hooks/useAPIData";
function ProductList() {
  const { loading, data, error } = useAPIData(
    "https://mocki.io/v1/bf70f69a-ed5b-495a-aa66-2ebb021dd3ce"
  );

  if (loading) {
    return <div>Loading...</div>;
  }

  if (data && data.products.length > 0) {
    return (
      <div>
        {data.products.map((product: any) => (
          <div key={product.id}>
            <h3>{product.name}</h3>
            <p>{product.price}</p>
          </div>
        ))}
      </div>
    );
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

  return <div>No data</div>;
}

export default ProductList;

This is a React component named ProductList that uses the useAPIData custom hook to fetch product data from a specified URL and render it in the component.

The component first calls the useAPIData hook with a mock URL that returns a JSON response containing an array of product data. The hook returns an object containing the loading, data, and error states that are then destructured for use in the component.

The component uses conditional rendering to handle different states of the loading, data, and error states.

If the loading state is true, the component returns a loading message “Loading…”.

If the data state exists and the length of the products array is greater than 0, the component maps over the array and returns a product card for each product, which includes the product’s name and price.

If the error state exists, the component returns an error message with the error message received from the useAPIData hook.

If none of the above conditions are met, the component returns a message “No data”.

Finally, the ProductList component is exported for use in other components.

Update “App.tsx” as below.

import React from "react";
import "./App.css";
import ProductList from "./components/product-list";

function App() {
  return (
    <div className="App">
      <ProductList />
    </div>
  );
}

export default App;

This is a simple React component named App that renders the ProductList component inside a div with the class name “App”. The ProductList component is imported from the ./components/product-list file.

This component doesn’t have any additional logic, and it serves as the entry point of the application. It simply renders the ProductList component, which fetches and displays a list of products using the useAPIData hook. The className attribute is used to apply styling to the div element using CSS.

Finally, the App component is exported to be used in other parts of the application.

Now lets run the application using npm start and see the browser output. If everything works correctly, you should have output as below.

so, we can see our custom react hook is working correcly.

Summary

The blog post discusses Custom React Hooks, which are functions designed to encapsulate stateful logic and reusable across multiple components. The post explains why custom hooks are needed and how they differ from regular functions. The blog also demonstrates how to create a custom React hook using TypeScript and Axios to fetch data from an API, manage loading and error states, and return an object containing these values. The post provides code examples and step-by-step instructions to create a new React application and use TypeScript with it. The blog also includes a mock API and shows how to use it to generate fake data.

Leave a Comment