Reusing Logic with Custom Hooks

♻️ Reusing Logic in React

One of the greatest strengths of React is the ability to reuse logic instead of duplicating it across components. As applications grow, multiple components often require the same state management, side effects, or event handling. Custom Hooks provide a clean and reusable way to share this logic while keeping components focused on rendering.

Important

Custom Hooks allow you to reuse logic, not UI or state. Every component that uses a custom Hook maintains its own independent state.

🎯 Why Reuse Logic?

Duplicating the same logic across multiple components increases maintenance costs and makes applications harder to understand. By extracting common behavior into a custom Hook, you can write the logic once and reuse it anywhere.

  • Reduce duplicated code.
  • Keep components clean and focused.
  • Simplify maintenance and bug fixes.
  • Encourage modular and reusable application design.

🔄 How Logic Reuse Works

Multiple Components Need Similar Logic
Identify the Shared Behavior
Extract It into a Custom Hook
Return State and Helper Functions
Reuse the Hook Across Components

💻 Example 1: Duplicated Logic

Without a Custom Hook

function CounterA() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

function CounterB() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

Both components contain the same logic, resulting in unnecessary duplication.

💻 Example 2: Extracting the Logic

Creating useCounter

import { useState } from "react";

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  function increment() {
    setCount(current => current + 1);
  }

  return {
    count,
    increment
  };
}

The counter logic now exists in one reusable location.

💻 Example 3: Reusing the Hook

Multiple Components Using the Same Hook

function CounterA() {
  const { count, increment } = useCounter();

  return (
    <button onClick={increment}>
      {count}
    </button>
  );
}

function CounterB() {
  const { count, increment } = useCounter(10);

  return (
    <button onClick={increment}>
      {count}
    </button>
  );
}

Although both components share the same logic, each one has its own independent counter state.

💻 Example 4: Reusing Browser API Logic

useOnlineStatus

import {
  useState,
  useEffect
} from "react";

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

  useEffect(() => {
    function updateStatus() {
      setIsOnline(navigator.onLine);
    }

    window.addEventListener("online", updateStatus);
    window.addEventListener("offline", updateStatus);

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

  return isOnline;
}

Any component can now determine the browser's connection status by calling useOnlineStatus().

📊 Copying Code vs Reusing Logic

Copying LogicCustom Hooks
Code is duplicated.Logic is written once.
Changes require multiple updates.Changes happen in one place.
Harder to maintain.Easier to maintain.
Larger components.Smaller, focused components.

📅 Logic Reuse Lifecycle

🎯 Common Use Cases

Reuse API requests, loading states, and error handling across multiple components.

Share form validation, input management, and submission logic.

Wrap browser features such as window size, online status, geolocation, and local storage.

Reuse login, logout, session management, and user information throughout an application.

⚠️ Common Mistakes

  • Copying code instead of extracting reusable logic.
  • Expecting multiple components to share the same state automatically.
  • Creating very large custom Hooks with multiple unrelated responsibilities.
  • Returning unnecessary values from a custom Hook.

Warning

Calling the same custom Hook in different components does not create shared state. Each call creates a separate instance of the Hook's state.

✅ Best Practices

  • Extract logic only when it is reused or logically grouped.
  • Keep custom Hooks focused on a single responsibility.
  • Return a minimal and well-defined API.
  • Compose several small Hooks instead of creating one large Hook.
  • Keep rendering logic inside components and business logic inside Hooks.

📚 Official Resource

Learn more about reusing logic with custom Hooks in the official React documentation at Reusing Logic with Custom Hooks.

Summary

Reusing logic with custom Hooks helps eliminate duplicate code while keeping React components simple and focused. By extracting shared behavior into reusable Hooks, developers can build cleaner, more maintainable, and scalable React applications without sharing component state between instances.