Custom Hooks

What's a custom hook?

A custom hook is just a normal javascript function whose name starts with keyword use. It can make use of react's built-in hooks like useState() , useEffect(), etc. Custom hooks usually return useful values for our components.

So why make a custom hook?

Custom hooks are no different than normal javascript functions and we usually make a function to extract some repetitive piece of code. The same reasoning is applicable here as well. If you have a state operation that is occurring in multiple components then there might be a possibility to extract a hook there.

The other reason can be readability, The normal useState() and useEffect() don't convey much meaning while reading the code. But let's say there is a hook called useTheme() or useToggle() it becomes very easy to guess what this hook must be doing. Hence, the code becomes more predictable, and the overall developer experience improves.

Separating state logic from component also has its own advantages let's say you are managing your state using useState() but one day you realised that state logic is getting is getting complicated and you need to implement useReducer() for state management. If you have a custom hook you will need not make any change inside your component it will be the same. All the changes will happen inside your hook.

Let's try to make our custom hook then.

Examples

1. useToggle()

This hook is useful when you want to toggle state(between true, and false). Toggling between states is used in case of open/close modal, or show less/more. Our hook will look something like this.

import { useState } from "react";

const useToggle = (initialState = false) => {
  const [state, setState] = useState(initialState);

  const toggle = () => {
    setState((prevState) => !prevState);
  };

  return [state, toggle];
};

export { useToggle };

useToggle() has its own state which is toggled using the toggle function. And its returns array just like useState(). This array has the existing state and toggle function. Now, this hook can be used in components to show/hide something.

import { useToggle } from "../hooks/useToggle";

const TextOption = () => {
  const [isTextVisible, toggleText] = useToggle(false);
  return (
    <div>
      <button
        onClick={() => {
          toggleText();
        }}
      >
        {isTextVisible ? "Hide" : "Show"}
      </button>
      {isTextVisible ? (
        <div>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dicta,
          officia!
        </div>
      ) : null}
    </div>
  );
};

export { TextOption };

2. useCounter()

No blog is complete without the classic counter example. So here it is. This is our useCounter() hook.

import { useState } from "react";

const useCounter = (initialState = 0) => {
  const [count, setCount] = useState(initialState);

  const incrementCount = () => {
    setCount((count) => count + 1);
  };

  const decrementCount = () => {
    setCount((count) => count - 1);
  };

  return { count, incrementCount, decrementCount };
};

export { useCounter };
const { count, incrementCount, decrementCount } = useCounter(0);

const Counter = () => {
    return (
      <>
        <h1>{count}</h1>
        <button onClick={incrementCount}>+1</button>
        <button onClick={decrementCount}>-1</button>
      </>
    );
  };

Conclusion

Similarly, you can extract other kinds of hooks as well. But one thing which you should avoid is early optimization which means directly trying to write an optimized version of the code. It's better to first write the logic inside the component using in-built hooks and then think of extracting the hook.

Thanks for reading.

Refrences

  1. useHooks