Take Control   of Your React Components with Custom Hooks: A Beginner's Guide

Take Control of Your React Components with Custom Hooks: A Beginner's Guide

ยท

4 min read

You must have heard about the custom hook in React, and so do I but never really understood how to create. But this time I build a project like Airbnb that helped me to understand it. Let's explore the concept behind it!

But wait !! are the hooks available not sufficient?

yes ! they are, but using their combination will give you magical power (just kidding), it helps to write clean and less code.

Fetching data using the hooks we have

We will develop a component that retrieves and displays a list of all the available rooms


import {useState,useEffect} from "react"
function RoomList() {
const[room,setRoom]=useState([])
  useEffect(()=>{
// stays.json : file that contain all room lists
        fetch("/stays.json")
        .then(data=>data.json())
        .then((stays=>{
            setRoom(stays)
        }))
    },[])
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
      {
        room.map((room) => {
          return (
<div>
<picture className=' image-container  '>
        <img className='w-full h-auto max-h-96 md:max-h-72 object-cover rounded-3xl md:rounded-2xl' src={room.photo} alt="room-photo" />
      </picture>
<h3 className='title text-lg font-semibold'>{room.title}</h3>
</div>)
        })
      }
    </div>
  )
}

In the above code, we are fetching data from stays.json or using any API to get data, Here I assume that you know how to use the useState and useEffect hooks.

But the above code has not much flexibility like how to fetch data from the different URL in the same component and Everytime we have to use useEffect for fetching in another component as well

Now, let's create ๐Ÿš€ a custom hook

#Example 1-useFetch hook

Now, we will create a custom hook that will solve our problem.

// Fetch.jsx
function useFetch(url){
const [data,setData]=useState(url)
useEffect(()=>{
// stays.json : file that contain all room lists
        fetch(url)
        .then(data=>data.json())
        .then((stays=>{
            setData(stays)
        }))
    },[])
return data
}
export default useFetch

In the above code, useFetch will take the URL as a parameter and it will return data fetched from the API.

After using the custom hook - useFetch

// App.jsx
import {useState,useEffect} from "react"
import useFetch from './Fetch.jsx'
function RoomList() {
// code after using custom hook
const room=useFetch('url')
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
      {
        room.map((room) => {
          return (
<div>
<picture className=' image-container  '>
        <img className='w-full h-auto max-h-96 md:max-h-72 object-cover rounded-3xl md:rounded-2xl' src={room.photo} alt="room-photo" />
      </picture>
<h3 className='title text-lg font-semibold'>{room.title}</h3>
</div>)
        })
      }
    </div>
  )
}

As we observe the current state of the code, it is evident that it has become increasingly clean and organized.

#Example 2 -useCustomContext hook

let's say we want to use useContext hook to store our state globally, so at first, we will create a context and export it for another component, it is old way or inefficient way write context

// Context.jsx
import { createContext } from 'react';
const RoomCtx=createContext([])
export default RoomCtx
// App.jsx
import RoomCtx from './Context.jsx'
function App() {
  return (
    <RoomCtx.Provider value={useFetch('url')}>
      <div className="App px-10 md:px-12 lg:px-16 ">
        <RoomList />
      </div>
    </RoomCtx.Provider>
  )
}

In the above Component App , we have provided the context value useFetch('url') that is returned from the custom hook that we have just created

// App.jsx
import {useState,useEffect,useContext} from "react"
import RoomCtx from './Context.jsx'
function RoomList() {
// code before using custom hook
const room=useContext(RoomCtx)
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
      {
        room.map((room) => {
          return (
<div>
<picture className=' image-container  '>
        <img className='w-full h-auto max-h-96 md:max-h-72 object-cover rounded-3xl md:rounded-2xl' src={room.photo} alt="room-photo" />
      </picture>
<h3 className='title text-lg font-semibold'>{room.title}</h3>
</div>)
        })
      }
    </div>
  )
}

In the RoomList component, for using the context we have to import useContext and RoomCtx but it is not a problem for a small application what if our codebase is too large, so every time we need to import useContext and RoomCtx that's why we need to create a custom hook so that need not import every time

After using the custom hook - useCustomContext

// Context.jsx

import { createContext } from 'react';
const RoomCtx=createContext([])
export RoomCtx
// creating a custom Hook for Context
function useCustomContext(){
return useContext(RoomCtx)
}
export  useCustomContext

Here we have just created a custom hook that will handle the import problem, Despite importing the useContext and RoomCtx, we have opted to create our hook and export it.

// App.jsx
import {RoomCtx} from './Context.jsx'
function App() {
  return (
    <RoomCtx.Provider value={useFetch('url')}>
      <div className="App px-10 md:px-12 lg:px-16 ">
        <RoomList />
      </div>
    </RoomCtx.Provider>
  )
}
// App.jsx
import {useState,useEffect,useContext} from "react"
import {useCustomContext}  from './Context.jsx'
function RoomList() {
// code bofore using custom hook
const {room}=useCustomContext()
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
      {
        room.map((room) => {
          return (
<div>
<picture className=' image-container  '>
        <img className='w-full h-auto max-h-96 md:max-h-72 object-cover rounded-3xl md:rounded-2xl' src={room.photo} alt="room-photo" />
      </picture>
<h3 className='title text-lg font-semibold'>{room.title}</h3>
</div>)
        })
      }
    </div>
  )
}

We utilized the useCustomContext hook to eliminate the need for importing both useContext and RoomCtx. This approach can also be applied to other components as necessary.

Conclusion

We have learned how to utilize a custom hook to streamline repetitive code. It's important to note when creating custom hooks, we utilize existing React hooks and return the desired outcome

ย