How to create a custom Hook in React with typescript?
Tags: react, typescript, javascript, webdev
Published: 2022-06-12 06:47:40

Typescript usage is growing day-by-day as many web developers are shifting to use React.js for solving custom requirements. With the introduction of react hooks in functional components, it becomes easier to develop more complex solutions for the real-world problems.

[React hooks](https://reactjs.org/docs/hooks-intro.html) are basically functions that let you “hook into” React state and lifecycle features from function components, and thus help us in solving problems using functional components rather than class components, which is more complex and confusing.

Creating custom hooks are the new industry practice and still many react developers find it 

So, here in this tutorial, I will make you understand what custom hooks are and how we can implement them in our own way. Here are a few points to keep in mind.

1. Custom hooks are basically functions that may or may not need some arguments and return something to the caller component.

2. Custom hooks name starts with the word `use` so that react identify it as a hook, otherwise your hook will act just as a normal function or component doing some task and returning something.

3. Hooks make your code more flexible and you do not need to write a solution again and again in different components and invoking those solutions.

Now, I am creating a hook to find the render count of a component. In this we are using useRef hook to use its current property.

```
import React, { useRef } from 'react';

const SHOW_RENDER_COUNTERS = true;

export const useRenderCounter = (): number | null => {
  const renderCount = useRef(0);
  renderCount.current = renderCount.current + 1;

  if (SHOW_RENDER_COUNTERS) {
    return renderCount.current
  }
  return null;
};
```

Now, whenever we wish to use this hook to find the render count we can use it like this:

```
const FindCount = () => {
  const renderCounter = useRenderCounter();

  return (
    <>
      <SomeComponentCode />
      {renderCounter}
    </>
  );
};
```

This is how we can create and use custom hooks.

Some other examples of custom hooks are:

### 1. Hook to Show tooltip when a user clicks on something.

```
import { useState, useRef, useEffect } from 'react'

export const useTooltip = (initialState: boolean) => {
  const ref = useRef<HTMLDivElement>(null)
  const [showTooltip, setShowTooltip] = useState<boolean>(initialState)

  const handleClick = (event: any) => {
    if (ref.current && !ref.current.contains(event.target)) {
      setShowTooltip(false)
    }
  }

  useEffect(() => {
    document.addEventListener('click', handleClick, true)

    return () => document.removeEventListener('click', handleClick, true)
  }, [ref])

  return { showTooltip, setShowTooltip, ref }
}

```

### 2. Hook to get the screen height.

```
import { useState, useEffect, useRef, RefObject } from 'react'

interface InterfaceSize {
  size: number
  sizeRef: RefObject<HTMLDivElement>
}
const useSize = (initialValue: number): InterfaceSize => {
  const sizeRef = useRef<HTMLDivElement>(null)
  const [size, setSize] = useState<number>(initialValue)

  useEffect(() => {
    setTimeout(() => {
      if (sizeRef.current) {
        setSize(sizeRef.current?.getBoundingClientRect().height)
      }
    }, 100)
  }, [size])

  return { size, sizeRef }
}

export default useSize

```

### 3. Hook that give alert when clicks outside of the passed ref.

```
import React, { useRef, useEffect } from "react";

/**
 * Hook that alerts clicks outside of the passed ref
 */
function useOutsideAlerter(ref: React.RefObject<HTMLInputElement>) {
  useEffect(() => {
    /**
     * Alert if clicked on outside of element
     */
    function handleClickOutside(event: Event) {
      if (ref.current && !ref.current.contains(event.target as Node))) {
        alert("You clicked outside of me!");
      }
    }
    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function OutsideAlerter(props) {
  const wrapperRef = useRef(null);
  useOutsideAlerter(wrapperRef);

  return <div ref={wrapperRef}>{props.children}</div>;
}
```