DEV Community

Cover image for React custom hooks for everyoneđŸȘ
djibril mugisho
djibril mugisho

Posted on ‱ Edited on

9 1

React custom hooks for everyoneđŸȘ

Maintaining react components that contain too much logic has never been easy, thanks to react custom hook, we can distribute our component's logic into a reusable function that can be imported into any component of our application. In case you are new to React, custom hooks are not special functions provided by React, instead, they are built on top of existing hooks.

In this project, we shall build an application to fetch a location based on the provided IP address, this project will be a favorable scenario for learning custom hooks since we practice both reusability and HTTP request within custom hooks.

Create application

In this project we shall be using Vite, if you are new to Vite don't worry everything you know about React remains the same. Run the command below for building your application, and for more information on Vite use the following link

npm create vite@latest myproject -- --template react-t
cd myproject
npm install 

//use the code editor of your choice 
Enter fullscreen mode Exit fullscreen mode

After creating the application, get rid of the App.css or delete all code inside of it, we don't need it in this project, all the styling will be written in the index.css file. To see the custom hooks in action we shall start without them and then change our logic to custom hook later.

css

* {
  margin: 0px;
  padding: 0px;
}

.container {
  max-width: 600px;
  min-height: 300px;
  margin: auto;
  margin-top: 40px;
  border: 0.5px solid rgba(0, 0, 0, 0.127);
  padding: 20px;
}

.container p
{
  margin: 20px 10px;
}

.button-container {
  max-width: 600px;
  margin: auto;
  margin-top: 20px;
  margin-bottom: 50px;
}

.button-container button {
  width: 100%;
  padding: 15px;
}
Enter fullscreen mode Exit fullscreen mode
import { useState } from 'react'

function App() {
  const [loading, setLoading] = useState<boolean>(false);
  const [location, setLocation] = useState<{} | any>();
  const [errorMessage, setErrorMessage] = useState<string>();

  const getLocation = async () => {
    try {
      setLoading(true);
      const request = await fetch("http://ip-api.com/json/"); //provide an ip address as request param if you don't want to use your current ip address e.g:http://ip-api.com/json/24.48.0.1"
      const response = await request.json();
      setLocation(response);
      setLoading(false)
    } catch (error: any) {
      //do what you want with the error 
      setLoading(false)
      setErrorMessage(error.message);
    }

  };

  return (
    <>
      <div className="container">
        <div className="location-info">
           // render location detail
          {location &&
            Object.keys(location).map((key) => {
              return <p><strong>{key}</strong>:  {location[key]}</p>
            })
          }

          {
            loading && <p>...loading</p>
          }
          {
            errorMessage && <p>{errorMessage}</p>
          }
        </div>
      </div>
      <div className="button-container">
        <button onClick={() => getLocation()}>Get location</button>
      </div>

    </>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

As you can the application is working perfectly fine, you click on the button you get the location, and everyone is happy 😎, but what if you want to do the same thing in other components of your application, do you imagine how many duplicated code you will end up with đŸ€”, don't worry let's solve that problem with a custom hook.

In this second example, I'm going to create a useGeoLocation hook that will provide all the states that we need, including the location.

useLocationHook

import { useState } from "react"


export const useGeoLocation = (): { location: any, errorMessage: string, loading: boolean, getLocation: (id?: string) => void } => {
    const [loading, setLoading] = useState<boolean>(false);
    const [location, setLocation] = useState<any>(); //i use any type for this state because i'm not sure about what will be returned;
    const [errorMessage, setErrorMessage] = useState<string>("");

    const getLocation = async (ip?: string) => {
        try {
            setLoading(true);
            const request = await fetch("http://ip-api.com/json/" + (ip ? ip : "")); //provide an ip address as request param if you don't want to use your current ip address e.g:http://ip-api.com/json/24.48.0.1"
            const response = await request.json();
            setLocation(response);
            setLoading(false)
        } catch (error: any) {
            setLoading(false)
            setErrorMessage(error.message);
        }
    }

    return {
        loading,
        location,
        errorMessage,
        getLocation
    }
}
Enter fullscreen mode Exit fullscreen mode

useLocation Hook in action


import { useGeoLocation } from './hooks/useGeoLocation';

function App() {
  const { loading, location, getLocation, errorMessage } = useGeoLocation();

  return (
    <>
      <div className="container">
        <div className="location-info">
          {location &&
            Object.keys(location).map((key) => {
              return <p><strong>{key}</strong>:  {location[key]}</p>
            })
          }

          {
            loading && <p>...loading</p>
          }
          {
            errorMessage && <p>{errorMessage}</p>
          }
        </div>
      </div>
      <div className="button-container">
        <button onClick={() => getLocation()}>Get location</button>
      </div>

    </>
  )
}

export default App

Enter fullscreen mode Exit fullscreen mode

Now you have a portable function that can be used anywhere in your application, you can go a bit deep and use useReducer instead dozen of use states, but since this article is about custom hooks, let's focus on that only.

You may think that states available in the useGeoLocation hook are shared among all components that call it, but that is not the case, each component that calls a custom hook will have its own separate instance of the hook's state, this allows you to use thing like useEffect or useLayoutEffect inside your custom hooks.

Conclusion

Custom hooks đŸȘ can improve the quality of your code and help you with reusable code 😊, use them as much as possible clean code always improves the productivity of your team.

If you find this article useful comment, or why not subscribeđŸ€”. Thanks for reading.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (4)

Collapse
 
leandro_nnz profile image
Leandro Nuñez ‱

Isn’t React built specifically for reusable components? Why adding extra packages to a project? Thanks in advance

Collapse
 
frontendengineer profile image
Let's Code ‱

you can imagine that useLocationHook is a piece of code that can be used by many React components. It is better use hooks for code reusability and avoid copying/pasting them over and over again.

Collapse
 
leandro_nnz profile image
Leandro Nuñez ‱ ‱ Edited

Ok. But react is specifically designed for you to do it by yourself. This package is just a shortcut. Why copying/pasting when you can create your custom hooks and reuse them everywhere?
It seems like it’s built for people without react knowledge only.
Please, if I’m not seeing something, let me know. I just want to understand.

Thread Thread
 
frontendengineer profile image
Let's Code ‱

*But react is specifically designed for you to do it by yourself. *
Yes and No. There are react libraries as well that one can tap to make dev life easier.

*Why copying/pasting when you can create your custom hooks and reuse them everywhere? *
That is what the author just showed everyone. To create a custom hook to promote code reuse

*It seems like it’s built for people without react knowledge only. *
Custom hooks can be easily learned just like any libraries or frameworks. It is not rocket science. Developers that doesn't have capability/eagerness to learn should find another role.

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❀ or a friendly comment on this post if you found it helpful!

Okay