Skip to content

React - The Power of Custom Hooks (DRY Code)

Posted on:January 8, 2026 at 10:00 AM

Hey everyone! 👋

Today we’re tackling a common habit that even I’m guilty of: Copy-Pasting Code.

You write a cool piece of logic to fetch data in one component. Then you need it in another component. Ctrl+C, Ctrl+V. Done, right?

Well, until you need to fix a bug in that logic. Now you have to fix it in 10 different places. 😫

Enter Custom Hooks.

This is the secret weapon to keeping your React components clean, readable, and—most importantly—DRY (Don’t Repeat Yourself).

The Problem: Repetitive Logic

Let’s say we have two components. Both need to track the window size (maybe for a responsive layout).

Here is Component A:

import { useState, useEffect } from "react";

const ComponentA = () => {
  const [windowSize, setWindowSize] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWindowSize(window.innerWidth);
    window.addEventListener("resize", handleResize);

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

  return <div>Window width is: {windowSize}</div>;
};

Now imagine Component B needs the exact same logic. You’d have to duplicate all that useState and useEffect code.

That’s a lot of boilerplate for just one number!


The Solution: Custom Hooks

A Custom Hook is just a JavaScript function. The only rule? It must start with “use”.

Let’s extract that window resizing logic into useWindowSize.

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

export const useWindowSize = () => {
  // 1. We just move the logic here!
  const [windowSize, setWindowSize] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWindowSize(window.innerWidth);
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  // 2. Return whatever the component needs
  return windowSize;
};

That’s it. Really. It’s just a function that calls other hooks.


The Result: Clean Components ✨

Now, let’s rewrite Component A using our new superpower.

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

const ComponentA = () => {
  // Look how clean this is!
  const width = useWindowSize();

  return <div>Window width is: {width}</div>;
};

And Component B?

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

const ComponentB = () => {
  const width = useWindowSize();

  return (
    <div style={{ backgroundColor: width > 768 ? "green" : "red" }}>
      Responsive Background!
    </div>
  );
};

Why is this awesome?

  1. Readability: Your component focuses on rendering, not logic.
  2. Reusability: Write once, use everywhere.
  3. Maintainability: If you need to change how the resizing works (e.g., adding a debounce), you change it in ONE place.

Closing

Custom Hooks aren’t some advanced, scary feature. They are just a way to organize your code better.

Next time you find yourself copying useEffect or useState logic, pause and ask: “Can I make this a hook?”

Your future self (and your teammates) will thank you.

Happy Coding! 🚀