custom hooks in react

How to Create Custom Hooks in React: Step-by-Step Guide (2025)

React has become one of the most widely used JavaScript libraries for building dynamic and interactive user interfaces. The introduction of React Hooks revolutionized the way developers manage component logic without relying on class components. However, as applications grow in complexity, reusing logic across multiple components can become challenging. This is where Custom Hooks in React play a vital role.

Custom hooks allow developers to extract reusable logic into separate functions, making code more organized, maintainable, and scalable. In this comprehensive guide, you will learn:

  • What custom hooks are and why they are useful
  • How to create custom hooks in React from scratch
  • Practical examples of custom hooks
  • Best practices to follow when writing custom hooks

By the end of this guide, you will be able to create your own custom hooks and use them effectively in your React projects.

What Are Custom Hooks in React?

Custom hooks in React are JavaScript functions that allow you to encapsulate reusable logic. They work similarly to built-in hooks like useState, useEffect, and useContext. However, custom hooks are tailored to perform specific tasks based on the needs of your application.

A custom hook is simply a function that starts with the prefix “use” and can utilize other hooks inside it to manage state or side effects.

Why Should You Use Custom Hooks?

Custom hooks offer several advantages, including:

  • Code Reusability: Extract reusable logic to avoid code duplication
  • Separation of Concerns: Keep components focused on UI rendering
  • Improved Readability: Simplify component code by delegating logic to hooks
  • Cleaner Code Structure: Organize application logic in smaller, reusable units

If your application involves repetitive logic such as data fetching, form validation, or state management, custom hooks can significantly improve your codebase.

How to Create Custom Hooks in React (Step-by-Step Guide)

Creating a custom hook involves writing a simple JavaScript function that uses built-in hooks to manage state or side effects.

Step 1: Create the Hook Function

Begin by creating a new function that starts with “use”. Let’s create a basic custom hook for managing a counter.

import { useState } from "react";

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

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  const reset = () => setCount(initialValue);

  return { count, increment, decrement, reset };
}

export default useCounter;

Step 2: Use the Custom Hook in a Component

Now let’s see how this custom hook can be used in a component.

import React from "react";
import useCounter from "./useCounter";

function CounterComponent() {
  const { count, increment, decrement, reset } = useCounter(5);

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default CounterComponent;

Explanation

In this example:

  • The useCounter hook encapsulates the logic for incrementing, decrementing, and resetting the counter.
  • The component only needs to focus on rendering the UI and calling the necessary functions from the hook.

Building a Custom Hook for API Calls (useFetch Hook)

Fetching data is a common task in React applications. Instead of writing the same API logic repeatedly, you can create a custom hook to manage API requests.

Step 1: Create the useFetch Hook

import { useState, useEffect } from "react";

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error("Failed to fetch data");
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Step 2: Use the useFetch Hook in a Component

import React from "react";
import useFetch from "./useFetch";

function UsersList() {
  const { data, loading, error } = useFetch("https://jsonplaceholder.typicode.com/users");

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {data.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default UsersList;

Explanation

  • The useFetch hook handles API requests and manages loading and error states.
  • The UsersList component only needs to call the hook and display the result.

Best Practices for Writing Custom Hooks

To ensure your custom hooks are efficient and maintainable, follow these best practices:

1. Start Hook Names with “use”

React uses this naming convention to detect hooks, so always prefix custom hooks with “use”.

2. Keep Hooks Focused on a Single Responsibility

Design each hook to handle only one specific task. This makes them easier to test and reuse.

3. Use Existing Hooks Inside Custom Hooks

Leverage built-in hooks like useState, useEffect, and useContext within your custom hooks.

4. Return Only Necessary Values

Expose only the values and functions that the component needs.

5. Minimize Side Effects

If your hook involves side effects, use useEffect with proper dependency arrays to avoid unnecessary re-executions.

Conclusion

Custom hooks in React are a powerful way to create reusable logic and improve code maintainability. By breaking down complex logic into smaller functions, you can simplify your components and enhance overall application performance.

In this guide, you learned how to create custom hooks for managing counters and API calls. You also explored best practices to write clean and reusable custom hooks.

Now it’s time to apply these concepts in your own projects. Start by identifying repetitive logic in your code and refactor it into custom hooks.

By mastering custom hooks, you can write more maintainable, scalable, and efficient React applications.