Basic Hooks for Your TypeScript Project

Written by lastcallofsummer | Published 2023/10/06
Tech Story Tags: web-development | react | react-hook | react-hooks | typescript | front-end-development | ui-interaction

TLDRExplore the transformative power of React hooks in modern frontend development. This article breaks down 5 essential custom hooks in TypeScript, enhancing code reusability and maintainability. Ideal for TypeScript and React developers aiming for cleaner and more efficient code.via the TL;DR App

If you're delving into modern front-end development, it's impossible to ignore the revolutionary changes that React hooks have brought to the table. Since their introduction in React 16.8, hooks have shifted paradigms, rendering class components almost archaic. No longer do you need to grapple with the complexities of class-based components to access state or lifecycle features; hooks have democratized these capabilities, making them accessible directly within functional components.

But why have hooks become such a game-changer? They excel in simplicity and reusability. Imagine crafting custom logic for a component and then effortlessly applying it elsewhere—without the rigmarole of higher-order components or tricky render props. This "write once, use anywhere" philosophy diminishes code redundancy, enhancing maintainability and scalability.

Yet the magic doesn't stop there. Hooks are incredibly composable; they allow you to package complex logic into custom hooks that can be seamlessly reused across components. This fine-tuned modularity not only declutters your components but also makes your codebase more testable. It’s akin to having a Swiss Army knife for every scenario you encounter—whether you're fetching data, handling subscriptions, or setting timers.

In a nutshell, hooks introduce an unprecedented level of order and efficiency to state management and side effects in your applications. Their intuitive structure turns your code into an easy-to-read, easy-to-maintain masterpiece. For many developers, hooks are not just another feature; they are the cornerstone that underpins truly modern React development.

Let's look into 5 essential hooks for your TypeScript project that will make your life easier.

1. Hook for Determining Screen Size: useBreakpoint

Media queries are a great way to adapt your interface for different devices. However, sometimes, you may need to manage this programmatically. The useBreakpoint hook allows you to determine the current screen size and provides information on the active "breakpoint."

use-breakpoint.ts

import { useState, useEffect, useMemo } from "react";

export const useIsClient = () => {
  const [isClient, setIsClient] = useState(() => typeof window !== "undefined");

  useEffect(() => {
    setIsClient(true);
  }, []);

  return isClient;
};

export function useBreakpoint() {
  const isClient = useIsClient();
  const [breakpoints, setBreakpoints] = useState({
    isS: false,
    isM: false,
    isL: false,
  });

  useEffect(() => {
    if (!isClient) return;

    const handleResize = () => {
      const width = window.innerWidth;
      const isS = width <= 348;
      const isM = width <= 720;
      const isL = width < 1120;

      setBreakpoints({ isS, isM, isL });
    };

    handleResize();
    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, [isClient]);

  return useMemo(() => breakpoints, [breakpoints]);
}

2. Hook for Detecting Click Outside an Element: useClickOutside

This hook is useful for, say, closing modal dialogs or dropdown menus when clicking outside them.

use-click-outside.ts

import React, { useEffect } from "react";

export function useClickOutside<T extends HTMLElement>(
  refs: React.MutableRefObject<T | null>[],
  callback: (event: MouseEvent) => void,
): void {
  const handleClick = (e: MouseEvent): void => {
    if (!refs.some((ref) => ref.current && ref.current.contains(e.target as Node))) {
      return callback(e);
    }
  };

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

    return () => {
      document.removeEventListener("click", handleClick, true);
    };
  });
}

3. Hook for Hover Detection: useHover

Sometimes, you need to determine if a cursor is hovered over a particular element, for example, to show a tooltip. The useHover hook will do this for you.

use-hover.ts

import * as React from "react";

export function useHover(delay = 0): [React.MutableRefObject<any>, boolean] {
  const [value, setValue] = React.useState<boolean>(false);
  const ref = React.useRef<HTMLDivElement>(null);
  let timer: ReturnType<typeof setTimeout>;

  const handleMouseOver = (): void => {
    if (timer) clearTimeout(timer);
    setValue(true);
  };

  const handleMouseOut = (): void => {
    timer = setTimeout(() => setValue(false), delay);
  };

  React.useEffect(() => {
    const node = ref.current;
    if (node) {
      node.addEventListener("mouseover", handleMouseOver);
      node.addEventListener("mouseout", handleMouseOut);

      return () => {
        if (timer) clearTimeout(timer);
        node.removeEventListener("mouseover", handleMouseOver);
        node.removeEventListener("mouseout", handleMouseOut);
      };
    }
  }, [delay]);

  return [ref, value];
}

4. Hook for Device Detection: useMobileDetect

Identifying the type of device can be useful for responsive design or for features available only on certain devices.

use-mobile-detect.ts

import * as React from "react";

export const getMobileDetect = (userAgent: string) => {
  const isAndroid = (): boolean => Boolean(/Android/i.exec(userAgent));
  const isIos = (): boolean => Boolean(/iPhone|iPad|iPod/i.exec(userAgent));
  const isOpera = (): boolean => Boolean(/Opera Mini/i.exec(userAgent));
  const isWindows = (): boolean => Boolean(/IEMobile/i.exec(userAgent));
  const isSSR = (): boolean => Boolean(/SSR/i.exec(userAgent));

  const isMobile = (): boolean => Boolean(isAndroid() || isIos() || isOpera() || isWindows());
  const isDesktop = (): boolean => Boolean(!isMobile() && !isSSR());
  return {
    isMobile,
    isDesktop,
    isAndroid,
    isIos,
    isSSR,
  };
};
export const useMobileDetect = () => {
  const userAgent =
    typeof window === "undefined" || typeof window.navigator === "undefined" ? "SSR" : window.navigator.userAgent;
  return getMobileDetect(userAgent);
};

5. Hook for Scroll Position: useScrollPosition

The useScrollPosition hook lets you know the current scroll position, which can be useful for implementing "sticky" headers or other UI elements that depend on scroll position.

use-scroll-position.ts

import * as React from "react";

export function useScrollPosition(): [React.MutableRefObject<any>, string] {
  const [position, setPosition] = React.useState<"fixed" | "relative">("fixed");
  const ref = React.useRef<HTMLDivElement>(null);
  const lastScrollY = React.useRef(0);

  React.useEffect(() => {
    const handleScroll = () => {
      const currentScrollY = window.scrollY;
      setPosition(currentScrollY < lastScrollY.current ? "fixed" : "relative");
      lastScrollY.current = currentScrollY;
    };

    window.addEventListener("scroll", handleScroll);

    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

  return [ref, position];
}

As we wrap up, it's clear that React hooks have revolutionized the way we approach modern front-end development. They have not only simplified the transition from class-based components to functional ones but have also provided a clean, reusable, and composable way to manage state and side effects. With hooks, you can say goodbye to cumbersome lifecycle methods and the intricacies of higher-order components. Instead, you get to embrace a streamlined way to share logic across components and build more maintainable, testable, and scalable applications.

We've covered 5 essential hooks that can elevate your TypeScript-based React projects. From determining screen size with useBreakpoint, to detecting clicks outside an element using useClickOutside, to hover detection via useHover, to device detection with useMobileDetect, and finally, scroll positioning through useScrollPosition. These hooks can serve as powerful tools in your developer toolkit, making your coding journey not just simpler but also more efficient.

Remember, the beauty of hooks lies in their modularity and reusability. They enable you to write concise, focused, and clean code that can be easily tested and debugged. For modern frontend developers, particularly those using TypeScript, these hooks are not just another feature—they are the cornerstone of effective and efficient React development.

So why wait? Start hooking into these utilities to make your TypeScript projects more robust, maintainable, and enjoyable to work on.

Happy coding!


Written by lastcallofsummer | hello here!
Published by HackerNoon on 2023/10/06