🪝 custom hook🪝

🪝 custom hook🪝

Custom React Hooks to make your Life Easier

Custom Hooks should be used when you notice yourself doing the same thing over and over again🔂 in different components.

From version 16.8, React Hooks are officially added to React.js. Besides built-in Hooks such as: useState, useEffect, useContext,useCallback…,

we can define our own hooks to use state and other React features without writing a class😲.

In addition to the familiar Hooks like useState, useEffect, useRef…, React also allows us to create custom Hooks with unique features that extract component logic into reusable functions.

Let’s take a look at the “what,” “how,” and “why” of writing our own Hooks😄.

What is a “Custom Hook?”🤔

"Building your own Hooks lets you extract component logic into reusable functions." -React Documentation

A custom Hook is really just a reusable function that follows the rules of Hooks:

  • Starts with “use”, i.e. useLocalStorage or useEventListener
  • Only calls other Hooks at the top level.
  • The Hook function is just like a normal function except it does not return any HTML, but instead, returns state functions and attributes.
  • To use the hook import it and use it within any other functional component. Example
    function MyProfile(){
      const auth = useAuth()
    }
    
    The function useAuth() is a hook.

It’s important that custom Hooks follow the useHook naming convention because it allows React tooling to ensure you’re following all the rules of Hooks and tells other developers what they’re dealing with.

Calling Hooks at the “top level” just means that we’re not doing it inside of loops, conditions, or nested functions. Hooks need to be called in the same order each time a component renders, so our calls have to stay outside of any program flow controls, like if statements.

when to use React custom hook?😶

When a piece of code (logic) is reused in many places(it’s easy to see when you copy a whole piece of code without editing anything, except for the parameter passed. Split like how you separate a function).

When the logic is too long and complicated, you want to write it in another file, so that your component is shorter and easier😉 to read because you don’t need to care about the logic of that hook anymore.

Detailed Explanation using example😃

Let’s take a look at an example.

  • we are going to be creating a new custom hook called useCounter. This hook will make it possible to reuse logic for a simple counter.

We are going to tackle this in two parts🤫

  1. First half we are going to implement a counter.
  2. In the second half we are going to extract the reusable logic into a custom hook.

So let's begin.😉

I am going to create a new file called counterOne.js. For the counter we need 3 basic scenarios.

  1. increment the counter
  2. decrement the counter
  3. reset the counter value
//1. first import useState from react

import React, { useState } from 'react'

function CounterOne() {
    const [count, setCount] = useState(0);
    //we define three methods increase,decrease and reset
    const increment = () => {
        setCount(prevCount => prevCount + 1)
    }
    const decrement = () => {
        setCount(prevCount => prevCount - 1)

    }
    const reset = () => {
        setCount(0)
    }
    return (
        <div>
            <h2>Count = {count}</h2>
            <button onClick={increment}>Increment</button>
            <button onClick={decrement}>Decrement</button>
            <button onClick={reset}>Reset</button>
        </div>
    )
}

export default CounterOne

1111.png

Now let's say we need the exact same counter functionality in a different component🤔

  • let's create a new file called CounterTwo.js And copy the same code from CounterOne and change its name CounterTwo.
  • finally include component in App.js
//This is CounterTwo component

import React, { useState } from 'react'

function CounterTwo() {
    const [count, setCount] = useState(0);
    //we define three methods increase,decrease and reset
    const increment = () => {
        setCount(prevCount => prevCount + 1)
    }
    const decrement = () => {
        setCount(prevCount => prevCount - 1)

    }
    const reset = () => {
        setCount(0)
    }
    return (
        <div>
            <h2>Count = {count}</h2>
            <button onClick={increment}>Increment</button>
            <button onClick={decrement}>Decrement</button>
            <button onClick={reset}>Reset</button>
        </div>
    )
}

export default CounterTwo

If you now take a look at the browser🧐 our second counter should also work as expected.

2222.png

But we do have one problem🤯

we are duplicating the code and how do we improve this?😟

the answer is creating a custom hook🤠

  • Create a new file useCounter.js this will be our custom hook for reusing counter functionality.
  • Next, we are going to extract the reusable logic from the component and added it to the custom hook.
  • So remove the state variable along with the methods from components and paste it in useCounter.js

  • So now our custom hook has reusable logic but we need a way to access the count value and these methods from our component.

  • So instead of returning any jsx our custom hook is going to return an array of values.

//This is our useCounter hook
import { useState } from 'react'

function useCounter() {

//we have extracted this from our component which were using same logic
    const [count, setCount] = useState(0);
    const increment = () => {
        setCount(prevCount => prevCount + 1)
    }
    const decrement = () => {
        setCount(prevCount => prevCount - 1)

    }
    const reset = () => {
        setCount(0)
    }

// our custom hook is going to return an `array of values.`
    return [count, increment, decrement, reset]
}

export default useCounter
  • By doing this now we can access the value and the methods using array destructuring in the component.
import React from 'react'
import useCounter from './useCounter'

function CounterOne() {

//This is where we are using our hook in component instated of same code
    const [count, increment, decrement, reset] = useCounter()

    return (
        <div>
            <h2>Count = {count}</h2>
            <button onClick={increment}>Increment</button>
            <button onClick={decrement}>Decrement</button>
            <button onClick={reset}>Reset</button>

        </div>
    )
}

export default CounterOne
//same array destructuring in CounterTwo Component

const [count, increment, decrement, reset] = useCounter()

Our Component still works as expected😯 but this time we have written better code using our custom hook useCounter😮‍💨

Custom hooks benefits🤠

  • Completely separate logic from the user interface.
  • Reusable in many different components with the same processing logic. Therefore, the logic only needs to be fixed in one place if it changes.🤓
  • Share logic between components.
  • Hide code with complex logic in a component, make the component easier to read.

Conclusion🙆‍♀️

Custom Hooks enable exceptional flexibility in sharing logic previously unavailable in React components.

I hope this guide has given you a better understanding of creating your own React Hooks.

Thank you for reading.🥰

Did you find this article valuable?

Support Chhakuli Zingare by becoming a sponsor. Any amount is appreciated!