React Custom Hooks: Reuse Logic and Simplify Complex Components
Last updated 2 months, 2 weeks ago | 146 views 75 5

Introduction: Why React Custom Hooks Matter
React provides built-in hooks like useState
, useEffect
, and useContext
to manage state and side effects. But when your components start growing in size and logic becomes repetitive—copying and pasting useEffect
blocks all over the app is not scalable.
That’s where custom hooks come in.
React Custom Hooks let you:
-
Extract reusable logic from components.
-
Keep components clean and focused on rendering.
-
Encapsulate and test side effects or shared functionality more easily.
If you find yourself writing similar useState
and useEffect
code in multiple components, you probably need a custom hook.
What Are Custom Hooks in React?
A custom hook is a JavaScript function that:
-
Starts with the word
use
-
Can call other hooks inside it (like
useState
,useEffect
,useReducer
, etc.) -
Returns stateful logic or behavior
Syntax
function useCustomHook() {
// useState, useEffect, etc.
return value;
}
Step-by-Step Guide to Creating a Custom Hook
1. Identify Repetitive Logic
Example scenario: multiple components track window width using the same logic.
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
Instead of duplicating this in every component, extract it into a custom hook.
2. Create the Custom Hook
// useWindowWidth.js
import { useState, useEffect } from 'react';
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Cleanup
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
export default useWindowWidth;
3. Use It in Your Components
import React from 'react';
import useWindowWidth from './useWindowWidth';
function ResponsiveComponent() {
const width = useWindowWidth();
return (
<div>
<h2>Window width: {width}px</h2>
{width < 600 ? <p>Mobile View</p> : <p>Desktop View</p>}
</div>
);
}
You’ve now abstracted logic and made it reusable and cleaner!
✅ Complete Example: Custom Hook for Fetching Data
// useFetch.js
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
fetch(url)
.then((res) => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
})
.then((data) => {
if (isMounted) {
setData(data);
setLoading(false);
}
})
.catch((err) => {
if (isMounted) {
setError(err.message);
setLoading(false);
}
});
return () => {
isMounted = false;
};
}, [url]);
return { data, loading, error };
}
export default useFetch;
// App.js
import React from 'react';
import useFetch from './useFetch';
function App() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/posts/1');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h2>{data.title}</h2>
<p>{data.body}</p>
</div>
);
}
export default App;
Tips & Common Pitfalls
✅ Best Practices
-
Name hooks with
use
prefix so React knows how to handle them. -
Keep hooks focused—each should do one thing (e.g., useWindowWidth, useLocalStorage).
-
Reuse hooks across multiple components to keep DRY.
⚠️ Common Pitfalls
-
Calling hooks conditionally inside your custom hook (bad pattern).
-
Returning JSX from custom hooks (they should only return logic or state).
-
Forgetting to return values needed by the consuming component.
-
Ignoring cleanup in
useEffect
—can lead to memory leaks.
Comparison Table: Built-in vs Custom Hooks
Feature | Built-in Hooks (useState, useEffect, etc.) | Custom Hooks |
---|---|---|
Provided by React | ✅ Yes | ❌ No (user-defined) |
Reusable | ⚠️ With boilerplate | ✅ Highly reusable |
Returns | State, updater, effects | Anything: state, functions, etc |
Typical use cases | State, side effects, context | Encapsulated logic reuse |
✅ Use Cases for Custom Hooks
-
Fetching data from APIs
-
Debouncing input
-
Listening to window events
-
Managing form state
-
Persisting data in localStorage
Conclusion: Level Up with React Custom Hooks
Custom hooks are one of the most powerful features in modern React. They promote cleaner code, better separation of concerns, and reusable logic without reaching for external state management libraries.
If you find yourself copying and pasting stateful logic, it’s a signal to extract a custom hook.
Actionable Takeaways
-
Use custom hooks to encapsulate logic and reduce repetition.
-
Keep each custom hook focused on one job.
-
Don’t return JSX—return logic, data, or functions.
-
Use
useEffect
,useState
, and other hooks inside your custom hook safely.