Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 5 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 25, 20264 min read

Introduction to Custom Hooks: Master Abstraction in React

Learn how to use custom hooks to achieve code reuse and clean code in React. Discover how to identify extractable logic and follow the Rules of Hooks.

ReactHooksCustom HooksClean CodeAbstractionJavaScriptfrontend

Previously in this course, we explored how to optimize our components by managing function stability with useCallback and preventing unnecessary re-renders using useMemo. While those tools keep our components performant, our codebase often suffers from another issue: logic duplication.

In this lesson, we move beyond built-in hooks and start building our own. By learning how to implement custom hooks, you’ll gain the ability to move complex, recurring logic out of your UI components and into reusable, testable functions.

Why Custom Hooks?

In a dashboard application, you’ll frequently find yourself writing the same state management logic across multiple components. Perhaps you're managing a "loading" toggle, tracking window dimensions, or syncing form fields with internal state.

If you copy-paste that logic, you create a maintenance nightmare. If you need to change how that logic works later, you have to find and update it in five different places. Custom hooks provide a way to perform abstraction, allowing you to encapsulate that logic and share it across your entire application. Think of this as the React equivalent of the Laravel helpers: How to build and use custom global functions pattern—it's about making your core logic reusable and clean.

Identifying Logic to Extract

A good candidate for a custom hook is any logic that uses one or more built-in hooks (useState, useEffect, useRef, etc.) and repeats across your project.

Look for these "code smells" in your components:

  1. Shared State: Multiple components need to track the same kind of data.
  2. Side Effects: Components have identical useEffect setups (e.g., event listeners or API subscriptions).
  3. Complex State: A component’s useState logic is so dense it obscures the actual UI rendering.

Worked Example: Creating a useToggle Hook

Let's look at a common pattern: toggling a boolean value, like a modal visibility state or a "dark mode" switch.

Before: Repetitive Logic

JSX
function SettingsModal() {
  const [isOpen, setIsOpen] = useState(false);
  const toggle = () => setIsOpen(prev => !prev);

  return <button onClick={toggle}>{isOpen ? CE9178">'Close' : CE9178">'Open'}</button>;
}

If we have three different components that need this, we're repeating useState and the toggle function.

After: The Custom Hook

We can extract this into a function named useToggle. By convention, custom hooks must start with the word use.

JAVASCRIPT
// hooks/useToggle.js
import { useState } from CE9178">'react';

export function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  const toggle = () => setValue((prev) => !prev);
  
  return [value, toggle];
}

Now, our component becomes significantly cleaner:

JSX
import { useToggle } from CE9178">'./hooks/useToggle';

function SettingsModal() {
  const [isOpen, toggle] = useToggle(false);

  return <button onClick={toggle}>{isOpen ? CE9178">'Close' : CE9178">'Open'}</button>;
}

This is the essence of Refactoring for Clean Code: Improving React Maintainability. We have successfully abstracted the state management away from the UI.

The Rules of Hooks

Because custom hooks use built-in hooks under the hood, they are bound by the same Rules of Hooks:

  1. Only call hooks at the top level: Never call a custom hook inside loops, conditions, or nested functions. React relies on the call order to track state.
  2. Only call hooks from React functions: You can call custom hooks from components or other custom hooks, but not from regular JavaScript functions or class components.

Hands-on Exercise

In our dashboard project, we often need to track if a component is currently "hovered."

  1. Create a new file hooks/useHover.js.
  2. Use useState to track a boolean isHovered.
  3. Use useRef to target the element.
  4. Implement useEffect to attach mouseover and mouseout event listeners to that element.
  5. Return the isHovered boolean and the ref object.

Hint: Remember that useEffect cleanup is essential to remove those event listeners when the component unmounts.

Common Pitfalls

  • Naming Conventions: If you name your function toggle instead of useToggle, React’s linting tools won't know it's a hook, and you won't get warnings if you violate the Rules of Hooks. Always prefix with use.
  • Over-abstraction: Don't turn every 2-line state change into a hook. If the logic is specific to one component and won't be reused, keep it inside the component to avoid unnecessary complexity.
  • Stale Closures: If your custom hook uses useEffect with dependencies, ensure those dependencies are passed correctly. If you're struggling with stale data, revisit Persistent Mutable Values with useRef.

Recap

Custom hooks are the primary mechanism for code reuse in modern React. By extracting stateful logic, you keep your components focused on rendering UI rather than managing complex side effects. As you continue to build your dashboard, look for opportunities to turn repeated logic into clean, reusable abstractions.

Up next: We will apply these principles to create a persistent useLocalStorage hook, enabling our dashboard settings to survive page reloads.

Previous lessonOptimizing Function References with useCallbackNext lesson Building a useLocalStorage Hook
Back to Blog

Similar Posts

ReactState ManagementJune 25, 20264 min read

Building a useLocalStorage Hook: Persistence & State Management

Learn to build a robust useLocalStorage hook. Master generic storage, JSON serialization, and cross-tab synchronization to keep your React app state persistent.

Read more
ReactJune 25, 20263 min read

Debouncing Search Input: Optimize API Requests in React

Part of the course

Intermediate React: Hooks, State & Data Patterns

intermediate · Lesson 5 of 48

  1. 1

    Mastering useRef for DOM Access

    4 min
  2. 2

    Persistent Mutable Values with useRef

    4 min
  3. 3

    Memoizing Expensive Calculations with useMemo

    3 min

Stop overwhelming your server with every keystroke. Learn how to implement debouncing in React to optimize API performance and create snappier UIs.

Read more
ReactJune 25, 20263 min read

Managing Errors: Professional Error Handling in React

Learn professional error handling in React. Discover how to catch API failures, store error messages in state, and provide clear UI feedback to your users.

Read more
4

Optimizing Function References with useCallback

3 min
  • 5

    Introduction to Custom Hooks

    4 min
  • 6

    Building a useLocalStorage Hook

    4 min
  • 7

    Refactoring Dashboard Settings

    4 min
  • 8

    Complex State with useReducer

    3 min
  • 9

    Managing Object-Based State

    3 min
  • 10

    Introduction to Context API

    Coming soon
  • 11

    Architecting Global State with Context and Reducer

    Coming soon
  • 12

    Implementing Theme Context

    Coming soon
  • 13

    Structuring State for Performance

    Coming soon
  • 14

    Handling Authentication State

    Coming soon
  • 15

    Integrating Reducers with Auth State

    Coming soon
  • 16

    Introduction to React Router

    Coming soon
  • 17

    Dynamic Routing with URL Parameters

    Coming soon
  • 18

    Nested Routes and Layouts

    Coming soon
  • 19

    Protected Routes for Authenticated Views

    Coming soon
  • 20

    Programmatic Navigation

    Coming soon
  • 21

    Building the Dashboard Navigation Structure

    Coming soon
  • 22

    Asynchronous Data Lifecycle

    Coming soon
  • 23

    Caching Strategies with React Query

    Coming soon
  • 24

    Mutations and Data Updates

    Coming soon
  • 25

    Synchronizing Client and Server State

    Coming soon
  • 26

    Integrating Live Data into the Dashboard

    Coming soon
  • 27

    Error Handling and Loading UI

    Coming soon
  • 28

    Controlled vs Uncontrolled Components

    Coming soon
  • 29

    Real-time Form Validation

    Coming soon
  • 30

    Schema-based Validation with Zod

    Coming soon
  • 31

    Handling Multi-step Forms

    Coming soon
  • 32

    Optimizing Form Submissions

    Coming soon
  • 33

    Performance Profiling with React DevTools

    Coming soon
  • 34

    Refactoring for Scalability

    Coming soon
  • 35

    Finalizing Dashboard Data Flow

    Coming soon
  • 36

    Deploying the Application

    Coming soon
  • 37

    Advanced Hook Composition

    Coming soon
  • 38

    Implementing Middleware for State

    Coming soon
  • 39

    Advanced Context Patterns

    Coming soon
  • 40

    Router Loaders and Data Prefetching

    Coming soon
  • 41

    Complex Route Guards

    Coming soon
  • 42

    Handling Large Datasets in UI

    Coming soon
  • 43

    Testing Hooks and Components

    Coming soon
  • 44

    Managing Global Modals

    Coming soon
  • 45

    Implementing Keyboard Shortcuts

    Coming soon
  • 46

    Optimizing Asset Loading

    Coming soon
  • 47

    Internationalization Basics

    Coming soon
  • 48

    Managing WebSocket Connections

    Coming soon
  • View full course