How to create your own custom Hooks in React (extensive guide)

How to create your own custom Hooks in React (extensive guide)

Let's understand creating React custom Hooks with examples.

Introduction

What are custom Hooks

Hooks are reusable functions.

When you have component logic that needs to be used by multiple components, we can extract that logic to a custom Hook.

Custom Hooks start with "use". Example: useFetch. use should be a must.

Why and when to use custom React Hooks

Custom hooks are an essential part of React. As a React developer, it is essential for you to learn to create custom Hooks to solve problems or to add extra features to your React project.

The main reason to write a custom Hook is code reusability. For example, instead of writing the same code again and again in different components that use the same logic, you can write that code inside a custom Hook and reuse it.

Rules of Hooks

The general rules of Hooks also applied to custom Hooks.

  • Only call Hooks at top levels.
  • Only call Hooks from React functions.
  • Don't call Hooks from regular JavaScript functions.

Creating a custom Hook

useFetch

Suppose our custom Hook name is useFetch. Let's say we are calling an API and fetching data. Then show the title from that data to the page.

Scenario without custom Hook

import { useState, useEffect } from "react";

const Home = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/todos")
      .then((res) => res.json())
      .then((data) => setData(data));
 }, []);

  return (
    <>
      {data &&
        data.map((item) => {
          return <p key={item.id}>{item.title}</p>;
        })}
    </>
  );
};

Scenario with custom Hook

We may need the fetch logic in other components as well. So we can extract it out in a custom Hook.

import useFetch from "./useFetch";

const Home = () => {
  const [data] = useFetch("https://jsonplaceholder.typicode.com/todos");

  return (
    <>
      {data &&
        data.map((item) => {
          return <p key={item.id}>{item.title}</p>;
        })}
    </>
  );
};

Here we can see that we are passing the API in useFetch Hook. And it is returning us the data. Which we are using further. Below is the logic for that Hook, that we have extracted from API part.

Custom Hook logic

import { useState, useEffect } from "react";

const useFetch = (url) => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => setData(data));
  }, [url]);

  return [data];
};

The logic goes as follows:

  • use keyword is used before the function name to make react understand that it is a Hook.
  • Our own custom Hook is also using Hooks provided by React.
  • After using API fetch logic, we return state data
  • That's it. 😲

wow, cool

Let's move to another example

useLocalStorage

Let's say our custom Hook name is useLocalStorage. Suppose we are making a counter app. When we click on the button counter value will be added to local storage. And then we will get value from localStorage and show to our page.

Scenario without custom Hook

function Counter(){
  const [counter, setCounter] = useState(()=>{
    let value;
    try{
      value = JSON.parse(
        window.localStorage.getItem('my-count') || '0');
    }
    catch(e){
      value = 0;
    }
    return value;
  });

  useEffect(()=>{
    window.localStorage.setItem('my-count', count);
  },[count]);

  return (
    <div>
      <button onClick={()=> setCount(count + 1)}>{count} 
      </button>
    </div>
  )
}

Working of the code

  • getting value from localStorage, if it's not present setting it to 0.
  • On every click update the counter value in localStorage

Now, what if you have to build another counter app and increase that counter value by 5. Now for that, you have to write the same logic again. That's not a good idea to write the same logic again. Let's wrap it up into a custom Hook and use that.

Scenario with custom Hook

function Counter(){
  const [counter, setCounter] = useLocalStorage('my-count',0);

return (
    <div>
    <button onClick={()=> setCount(count + 1)}>{count}</button>
    </div>
  )
}

Here we can see that we have used our localStorage Hook. And passed the key and initial value for localStorage. And it is returning us state and setState.

Custom Hook logic

function useLocalStorage(key, defaultValue){
  const [state, setState] = useState(()=>{
    let value;
    try{
      value = JSON.parse(
        window.localStorage.getItem(key) || String(defaultValue));
    }
    catch(e){
      value = defaultValue;
    }
    return value;
  });

  useEffect(()=>{
    window.localStorage.setItem(key, state);
  },[state]);

  return [state, setState]

}

We have extracted out the localStorage logic from our code and put into the custom Hook. The logic goes as follows:

  • use keyword used before function name.
  • Here we are taking key and defaultValue are parameters.
  • Here we have used useState Hook.
  • After all things, in the end we are returning [state, setState].

Now, this looks better. Wherever we need localStorage logic we can use our own Hook. We can give any name for key and any default value while calling our Hook.

yes! gif

Cool facts

Have you noticed, that we returned data in an array and not as an object. But why? Because

If a Hook returns an array ([x]), then you are able to name the variables yourself.

If a Hook returns an object ({x}), then you must use the same variables names as returned by the Hook itself.

You have seen that when we use useState Hook. we can write any name. eg. const [data, setData] = useState() or const [isModalOpen, setIsModalOpen] anything. 🤯

Use cases

If we are going to be using multiple instances of a Hook in a single component, then use array return.

If our component will only have 1 (or few instances) of a Hook, use object return.

Conclusion

Here we have discussed almost every aspect of custom React Hooks with examples. I hope this have helped you and now you will be able to create you own custom Hooks in React.

If you loved it. Please feel free to give your feedback or suggestions in comments. Also feel free to ask any query.

the end gif

You can also follow me on Twitter and LinkedIn