React custom Hooks are easy than you think !!

A simple guide to custom react hooks.

Β·

5 min read

Featured on daily.dev

Table of contents

No heading

No headings in the article.

ReactJS provides a lot of built-in hooks that you can use, but along with that we can also create our own custom hooks depending on our requirement.

When we have a component logic that needs to be used by multiple components, we can extract that logic to a custom Hook and use it on every component.

Custom hooks are nothing more than a normal javascript function whose name starts with "use". The main reason for creating custom hooks is to follow the "DRY" (Don't repeat yourself) principle. We can simply create a custom hook and reuse it.

Before moving any further, let's see some examples of custom hooks which will help you in getting an idea on when to use custom hooks.

♾️ useInfiniteScroll hook: Suppose you had a website, in which you need to render a huge amount of data on the screen. So, instead of fetching all the data at once and rendering it on the user's screen you can fetch a fraction of data, and render it. Now when the user scrolls to the bottom of the page we can simply fetch the next fraction, and render it again. This saves our server bandwidth, improves response time and user experience.

infinite-scroll.gif

πŸ“„ useCopyToClipboard hook : You might have seen a little "copy to clipboard" button on code snippets (shown below). To implement such a feature, we can simply create this custom hook, and call it whenever and wherever we want.

copy-clipboard.png

⬇️ useFetch hook : It's job is to simply fetch data from an API and return it to the component. We will be implementing this hook in this tutorial. (this is how it will look)

custom-hook.png

So, now I hope that you might have some understanding about what exactly are custom hooks and when to use them. Let's start with the useFetchJoke hook.

For this tutorial, we will be creating a simple react app which will render a random dad joke using icanhazdadjoke api, and when we click on the "get new joke" button, our custom hook will send us a new joke. PRETTY SIMPLE, RIGHT !!

Create a new react app

npx create-react-app custom-hook-demo

Go make some β˜•, because it's gonna take a while now.πŸ₯² Run the server

npm start

Clean up the App.js file, so it looks like this,

// App.js

import './App.css';

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

export default App;

This will render a page with "Hello" as the heading. Copy-paste this style in your App.css file.

/* App.css */

.App {
  text-align: center;
  width: 70%;
  margin: auto;
}

header {
  min-height: 20vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 100px;
  color: white;
  margin-bottom: 50px;
}

.joke {
  background-color: #282c34;
  padding: 40px;
}

.new_joke {
  float: right;
  padding: 10px;
  font-size: 20px;
  margin-top: 20px;
  color: #282c34;
}

.new_joke:hover {
  cursor: pointer;
}

.joke p{
  padding: 0;
  font-size: x-large;
  line-height: 35px;
}

Now we will be creating our useFetchJoke hook. Create a new file named useFetchJoke.js

// useFetchJoke

import { useEffect, useState } from "react";

export default function useFetchJoke() {
    const [joke, setJoke] = useState('');

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

    async function getNewJoke() {
        setJoke('Loading...')
        const res = await fetch('https://icanhazdadjoke.com/', {
            headers: {
                Accept: 'application/json'
            }
        });
        const data = await res.json();
        setJoke(data.joke);
    }

    return [joke, getNewJoke];
}

So first we have a state named joke, which stores the actual joke string in it. The function setJoke is used to update this particular state.

Then we have a built-in hook called useEffect (yes, you can use built-in hooks or even another custom hook inside of a custom hook). useEffect contains a function and a list of dependencies. The dependency list contains a list of states, when any of the state is changed, the function present in useEffect is executed. If the dependency list is empty (as it is in our case) the function is executed only once when the component is first mounted.

What if we don't pass a dependency array ? console log something in your function and try it for yourself. πŸ˜‰

We have a function called getNewJoke(), as you might have guessed, it's the actual function which fetches a new joke from the api. Before requesting for a new joke from the api, we set the joke state to loading, this will print "loading.." instead of a joke on the screen, so the user will know that a new joke is being fetched.

We request a new joke from the icanhazdadjoke api, and set the joke state to the newly fetched joke, using setJoke function.

After all this, we return 2 things, our joke state and getNewJoke function.

So, here's the flow ( read it slowly), the joke state we just returned will be rendered in our component and when we click the "get new joke" button, getNewJoke function will be trigerred, which will fetch a joke and update our state, which will be reflected on the screen.

// App.js
import './App.css'
import useFetchJoke from './useFetchJoke';

function App() {

  const [joke, getNewJoke] = useFetchJoke();

  return (
    <div className="App">
      <header>Custom Hook</header>
      <div className='joke'>
        <p>{joke}</p>
      </div>
      <button className='new_joke' onClick={getNewJoke}>Get a new one !!</button>
    </div>
  );
}

export default App;

First of all, we called the useFetch hook, which returned us the joke state and a function to get a new joke. As we can see inside the paragraph tag we are rendering the joke and when the button is clicked, we are calling the getNewJoke function.

If you made it this far, then congratulations and thanks a lot. 😁

PS: This is actually my first post, and to be honest, writing actually takes up a lot of brain cells. I had a really hard time figuring out what to write, how to write etc..
Any feedback will be appreciated.

Β