Back to roadmaps react Course

Understanding Custom Hooks

One of the main benefits of React Hooks is the ability to share stateful logic between components without changing your component hierarchy (such as adding wrapper components). You can do this by creating Custom Hooks.


1. Sharing Logic vs Sharing State

A common point of confusion is whether custom hooks share state values between components.

  • No: Custom hooks do not share state values. Every time a component calls a custom hook, the hook runs its own isolated setup, state hooks, and side effects.
  • Yes: Custom hooks share the logic and behavior structure (how state is initialized, updated, and cleaned up).

2. Rules of Custom Hooks

Custom hooks must follow the same rules as React built-in hooks:

  • Prefix with "use": The function name must start with the word use (for example, useAuth or useWindowWidth). This naming convention tells React compiler tools to inspect the hook for violations of hook rules.
  • Only Call Hooks at the Top Level: Do not call hooks inside loops, conditions, or nested functions.
  • Only Call Hooks from React Functions: Call custom hooks only from React functional components or other custom hooks.

3. Extracting Logic into a Custom Hook

Let us look at a simple example: a component tracking network online status.

Monolithic Implementation

import { useState, useEffect } from "react";

function OnlineStatusIndicator() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);

    window.addEventListener("online", handleOnline);
    window.addEventListener("offline", handleOffline);

    return () => {
      window.removeEventListener("online", handleOnline);
      window.removeEventListener("offline", handleOffline);
    };
  }, []);

  return <h1>Status: {isOnline ? "Online" : "Offline"}</h1>;
}

Extracted Custom Hook

We can extract the online check logic into a separate, reusable custom hook:

// useOnlineStatus.js
import { useState, useEffect } from "react";

export function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);

    window.addEventListener("online", handleOnline);
    window.addEventListener("offline", handleOffline);

    return () => {
      window.removeEventListener("online", handleOnline);
      window.removeEventListener("offline", handleOffline);
    };
  }, []);

  return isOnline;
}

Now, any component in your application can consume this logic:

import { useOnlineStatus } from "./useOnlineStatus";

function NavbarIndicator() {
  const isOnline = useOnlineStatus();
  return <div className={isOnline ? "green-dot" : "red-dot"} />;
}
Published on Last updated: