Introduction
As React applications grow, developers often find themselves repeating the same logic across multiple components. Examples include fetching data from APIs, managing form inputs, handling authentication, or tracking browser events.
Duplicating logic makes applications harder to maintain and increases the chances of bugs. React Custom Hooks solve this problem by allowing developers to extract and reuse stateful logic across components.
In this article, you'll learn what React Custom Hooks are, why they're useful, and how to create them with practical examples.
What Are React Custom Hooks?
A Custom Hook is a JavaScript function that uses React Hooks such as:
useState
useEffect
useContext
useReducer
Custom Hooks allow developers to reuse logic without duplicating code.
A custom hook name must always start with:
use
Examples:
useFetch()
useAuth()
useWindowSize()
Why Use Custom Hooks?
Consider two components that fetch user data from the same API.
Without Custom Hooks:
Component A
↓
API Logic
Component B
↓
Same API Logic
The same code gets repeated.
With Custom Hooks:
Component A
↓
useFetch()
Component B
↓
useFetch()
Benefits include:
Cleaner code
Better reusability
Easier maintenance
Reduced duplication
Creating Your First Custom Hook
Let's create a simple hook that tracks a counter.
import { useState } from "react";
function useCounter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return { count, increment };
}
Using the hook:
function Counter() {
const { count, increment } = useCounter();
return (
<>
<p>{count}</p>
<button onClick={increment}>
Increase
</button>
</>
);
}
The counter logic is now reusable across multiple components.
Example: API Data Fetching Hook
Fetching data is one of the most common use cases.
Create a custom hook:
import { useState, useEffect } from "react";
function useUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users")
.then(response => response.json())
.then(data => setUsers(data));
}, []);
return users;
}
Use it inside a component:
function Users() {
const users = useUsers();
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
);
}
This eliminates repeated API logic.
Real-World Example
Imagine an e-commerce application.
Multiple pages need:
Current user information
Authentication status
User permissions
Instead of repeating logic:
useAuth()
can provide:
const { user, isLoggedIn } =
useAuth();
Every component can reuse the same authentication logic.
Rules for Custom Hooks
Follow React Hook rules:
Always start the name with "use"
Call hooks only at the top level
Don't call hooks inside loops
Don't call hooks inside conditions
Correct:
const data = useUsers();
Incorrect:
if (isLoggedIn) {
useUsers();
}
Advantages of Custom Hooks
Custom Hooks provide several benefits:
Reusable business logic
Cleaner components
Better code organization
Easier testing
Reduced duplication
Improved maintainability
They are especially useful in large React applications.
Best Practices
When creating Custom Hooks:
Keep hooks focused on one responsibility.
Use meaningful names.
Return only required data.
Handle errors properly.
Avoid overly complex hooks.
Document reusable hooks.
Following these practices makes hooks easier to maintain.
Conclusion
React Custom Hooks are one of the best ways to share and reuse business logic across components. They help reduce duplication, improve code organization, and make applications easier to maintain.
Whether you're managing API calls, authentication, forms, or browser events, Custom Hooks allow you to write cleaner and more scalable React applications. As your React projects grow, Custom Hooks become an essential tool for building reusable and maintainable code.