If you’ve ever found yourself reusing the same state logic across multiple React components, you’ve already discovered the perfect use case for custom hooks. Today, let’s break down what custom hooks are, why they matter, and how to build them with real-world examples.
What Exactly Are Custom Hooks?
Custom hooks are reusable JavaScript functions in React that allow you to extract component logic into standalone, sharable units. They always start with the prefix use (e.g., useAuth, useFetch) and internally leverage React’s default hooks like useState, useEffect, or others.
Examples:
useFetchuseToggleuseLocalStorage
Think of custom hooks as a way to package behavior, not UI.
🤔 Why Use Custom Hooks When React Already Has Hooks?
React’s built-in hooks are powerful—but repetitive logic across multiple components can quickly become messy. Custom hooks let you:
- Encapsulate repetitive logic (fetching, debouncing, form handling, auth, etc.)
- Keep components clean and focused on UI
- Share logic across the entire app
- Make your code more testable and modular
In short, custom hooks help you write cleaner, DRY-er, and more maintainable code.
Custom hooks help us:
- Avoid repeating code
- Keep components cleaner
- Reuse logic anywhere
- Organize complex logic in one place
How Logic Moves Into Custom Hooks
Any logic that we write inside a component can also live inside a custom hook:
-
useState(state) -
useEffect(side effects) - Functions
- Memoized values
- Event handlers
Here’s an example pattern:
function useExample() {
const [value, setValue] = useState(0);
useEffect(() => {
console.log("Value changed:", value);
}, [value]);
const increment = () => setValue(prev => prev + 1);
return { value, increment };
}
And in the component:
const { value, increment } = useExample();
The component stays clean, and the logic stays reusable.
Returning Multiple Values
A custom hook can return anything — objects, arrays, functions, booleans, etc.
Example:
function useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
return { count, increment, decrement };
}
Using the Same Custom Hook in Multiple Components
This is the real power of custom hooks. One hook → infinite usage.
function CounterA() {
const { count, increment } = useCounter(5);
return <button onClick={increment}>A: {count}</button>;
}
function CounterB() {
const { count, increment } = useCounter(10);
return <button onClick={increment}>B: {count}</button>;
}
Both use the same logic but keep separate state.
How To Create a Custom Hook
Rules:
- The name must start with
use - Hooks must be called at the top level (not inside loops or conditions)
- Hooks can be used inside components or custom hooks only
Simple Example: useToggle
import { useState } from "react";
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle];
}
export default useToggle;
Usage in a component:
const [isOpen, toggleOpen] = useToggle();
Reusing a Custom Hook in Multiple Components
Any component can simply import and call the hook:
export default function CounterUI() {
const { count, increment, decrement } = useCounter();
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
</div>
);
}
Each component gets its own isolated state, even though the logic is shared.
Real-World Examples Where Custom Hooks Are Super Useful
1. Data Fetching – useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
});
}, [url]);
return { data, loading };
}
2. LocalStorage Syncing – useLocalStorage
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [value]);
return [value, setValue];
}
Other Real-World Custom Hook Ideas
-
useDebouncefor search inputs -
useAuthfor login/session handling -
usePreviousfor tracking previous values -
useDarkModefor theme toggling -
useOnlineStatusto detect internet connectivity
Conclusion
Custom hooks unlock one of React’s greatest strengths: the ability to share logic cleanly and efficiently. They help you build scalable apps, reduce repetition, and keep components focused on UI—not complexity.
Today’s topic might feel small, but mastering custom hooks will make a huge difference as your projects grow.
Happy coding!
Top comments (0)