React Hooks • Reusable Logic
A Custom Hook is a reusable function in React that starts with the word use and allows you to extract and share logic between multiple components.
They make your code cleaner, reduce duplication, and improve maintainability — especially when working with complex logic like fetching data, form handling, or listening to browser events.
use (e.g., useFetch, useForm).useState, useEffect, etc.A custom hook is just a JavaScript function that:
use prefix (so React can track hook calls).useState, useEffect, etc.Conceptually, you are moving logic out of components into a shared function so that:
useCounter Hook
// useCounter.js - reusable counter logic hook
import { useState } from "react";
export default function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount((c) => c + 1);
const decrement = () => setCount((c) => c - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
// App.js - UI component that consumes useCounter
import React from "react";
import useCounter from "./useCounter";
function App() {
const { count, increment, decrement, reset } = useCounter(10);
return (
<div className="text-center">
<h4>Count: {count}</h4>
<button className="btn btn-primary me-2" onClick={increment}>+</button>
<button className="btn btn-danger me-2" onClick={decrement}>-</button>
<button className="btn btn-secondary" onClick={reset}>Reset</button>
</div>
);
}
export default App;
The useCounter hook encapsulates all counter-related logic: state, increment/decrement handlers, and reset. The App component simply renders buttons and displays the current count.
When you click +, the count increases; when you click -, it decreases; clicking Reset returns the count to the initial value 10. The same hook can be reused in any component that needs a counter.
useFetch Hook
// useFetch.js - reusable data fetching hook
import { useState, useEffect } from "react";
export default function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
setError(null);
fetch(url)
.then((res) => res.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((err) => {
setError(err);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
// UserList.js - component that consumes useFetch
import React from "react";
import useFetch from "./useFetch";
function UserList() {
const { data, loading, error } = useFetch(
"https://jsonplaceholder.typicode.com/users"
);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error fetching data!</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UserList;
The useFetch hook centralizes the logic for fetching data, tracking loading state, and handling errors. The UserList component only cares about how to render the result.
While data is loading, the user sees “Loading...”. If the request fails, an error message is shown. On success, a list of user names fetched from the API is rendered.
useWindowSize Hook
// useWindowSize.js - track browser window size
import { useState, useEffect } from "react";
export default function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return size;
}
// DisplaySize.js - shows current viewport dimensions
import React from "react";
import useWindowSize from "./useWindowSize";
function DisplaySize() {
const { width, height } = useWindowSize();
return (
<h5 className="text-center">
Width: {width}px | Height: {height}px
</h5>
);
}
export default DisplaySize;
The useWindowSize hook listens to the browser resize event and keeps the current width and height in state. The DisplaySize component simply shows those values.
As you resize the browser window, the numbers update automatically, making this hook useful for responsive layouts and adaptive components.
useAuth, useForm, useToggle).use so React can enforce the rules.useToggle hook that toggles between true/false.useLocalStorage hook that syncs state with browser localStorage.useOnlineStatus hook that detects when the user goes offline or online.Goal: Learn to design and implement reusable logic blocks in React using custom hooks — making your apps modular, efficient, and easy to maintain.