DEV Community

Cover image for Reusing Logic in React with Custom Hooks: a Practical guide
Kada Guetouache
Kada Guetouache

Posted on • Edited on

Reusing Logic in React with Custom Hooks: a Practical guide

Custom hooks are a powerful feature in React that are used for more specific purposes unlike React build-in hooks, and it's done by encapsulating common functionalities into independent functions. custom hooks promote re-usability, improve component organization and overall enhance code maintainability.

In this guide will dive into the purposes of using a custom hooks, understanding the fundamental of creating custom hook and how to use it other components. then we will illustrate a real world example by building a fetch API custom hook.

Understanding the basics

usually developer get scared of term custom hooks so lets demystify it.

a custom hooks is simply a function that start with the use prefix (which is crucial for the custom hooks to work).
this function consist of reusable logic that utilize React build-in hooks. usually you consider using a custom hook if you have same logic across multiple component so by utilizing custom hooks you can solve multiple issues like enhance code organization and maintainability.

Creating a simple custom hook

The example below is a simple counter custom hook that manages the count state using useState hook and update the count respectively using increment or decrement functions that only set the count state.

import { useState } from 'react'

const useCount = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(prev => prev + 1)
  const decrement = () => setCount(prev => prev - 1)

  return { count, increment, decrement }
}

export default useCount;
Enter fullscreen mode Exit fullscreen mode

congrats you just build your very own custom hooks it's pretty simple. next will dive into how to use this hook

Using custom hooks in components

using custom hooks in another components is simply done by destruction the returned values form the custom hook inside other components

import useCount from 'customHooks'

const Page = () => {
  const {count, increment, decrement} = useCount()

  return(
    <div>{ count }</div>
    <button onClick={increment}> + </button>
    <button onClick={decrement}> - </button>
  )
}

export default Page
Enter fullscreen mode Exit fullscreen mode

Real world example of using custom hook

one of the most repetitive logic is fetching an API an e-commerce site will fetch data for authentication, payment process, displaying all the products, comments, reviews ... etc.

you can imagine the amount of repetitive fetching logic across the application which can be simplified using a custom hook.

in this section will create a custom fetching hook.

we will be using useState and useEffect build-in React hooks
we are gonna have a state for data, a state of pending in case we want to show a spinner while the data is fetching and error state in case of fetch failure.

the code below is self explanatory. inside useEffect we define a fetchData function that is asynchronous and that will handle the fetching logic. below the useEffect the custom hook will return the following values which can be used in all other components data, pending, error.

notice that we are passing a url value to useFetch custom hook paramater which means that data can be passed to custom hooks

import {useState, useEffect} from 'react'

const useFetch = (url: string) => {
  const [data, setData] = useState<any>([])
  const [pending, setPending] = useState(false)
  const [error, setError] = useState(null)

  useEffect(() => {
    const fetchData = async () => {
      setPending(true)

      await fetch(url)
        .then(result => {
          if (!result.ok) throw new Error('something went wrong!')
          return result.json()
        })
        .then(result => {
          setData(result)
          setPending(false)
        })
        .catch(error => setError(error))
    }

   fetchData()
  }, [url])

  return { data, pending, error }

}

export default useFetch
Enter fullscreen mode Exit fullscreen mode

by using the useFetch hook inside Page components we can now display message to client in case of error, show a spinner while the data is fetching and finally display data to client.

this component can be used repeatedly across all the application which decreases the amount of repetitive code.

import useFetch from './hooks/useFetch'
import Spinner from "./icons/Spinner"

const Page = () => {
  const {data, pending, error} = useFetch('https://jsonplaceholder.typicode.com/posts')

  if(error) <div>Cloud not fetch data from the server</div>

  return(
    {pending ? 
     ( <Spinner />)
     :
     (
      data.map((item) => (
        <div>
          <h3>{item.title}</h3>  
          <p>{item.body}</div>
        </div>
       )
      )
    )}
  )
}

export default Page;
Enter fullscreen mode Exit fullscreen mode

Conclusion

Custom hooks offer a powerful mechanism for encapsulating and reusing logic within React components, By extracting common functionalities into a dedicated functions, you can enhance code organization, improve maintainability, and promote code re-usability.

We have explored the fundamentals of creating custom hooks, understanding how to use them within React components and show a real world example of using a custom hook.

Top comments (0)