React hooks have completely changed the way we write components. They allow us to handle state, side effects, and context in a cleaner, more functional way. But sometimes, we find ourselves writing the same hook logic again and again. That’s where custom hooks come to the rescue.
In this article, we’ll explore:
- What custom hooks are
- When to use them
- How to create and use them with real-world examples
What are Custom Hooks?
A custom hook is simply a JavaScript function whose name starts with use
and that can use other hooks inside it (useState
, useEffect
, useContext
, etc.).
They allow us to:
- Extract reusable logic from components
- Keep your components clean and focused
- Share logic between different components without duplicating code
Think of them as small utilities that encapsulate hook-related logic and can be plugged into any component.
When to Use Custom Hooks
You should consider creating a custom hook when:
Reusing logic:
If multiple components need the same piece of logic (e.g., fetching data, handling form inputs).
Improving readability:
Components should mainly focus on UI, not business logic. Moving logic to hooks makes code more readable.
Separation of concerns
Keeps logic modular and testable, just like splitting functions in regular JavaScript.
How to Create a Custom Hook
Let’s start with a real-world scenario: fetching data from an API.
Normally, we’d write the fetching logic inside a component with useEffect
. But if multiple components need to fetch data, we’ll end up repeating the same code.
Example 1: A Custom Hook for Fetching Data
import { useState, useEffect } from "react";
// Custom Hook
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Failed to fetch");
const result = await response.json();
if (isMounted) {
setData(result);
setError(null);
}
} catch (err) {
if (isMounted) setError(err.message);
} finally {
if (isMounted) setLoading(false);
}
}
fetchData();
return () => { isMounted = false; };
}, [url]);
return { data, loading, error };
}
Using it in a Component
function UsersList() {
const { data: users, loading, error } = useFetch("https://jsonplaceholder.typicode.com/users");
if (loading) return <p>Loading users...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Now, whenever we need to fetch data in another component, we just call useFetch(url)
instead of rewriting the same code.
Example 2: A Custom Hook for Form Handling
Forms are everywhere, and handling form state can get repetitive. Let’s create a reusable hook to manage form inputs.
import { useState } from "react";
export function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value,
});
};
const resetForm = () => setValues(initialValues);
return { values, handleChange, resetForm };
}
Using it in a Login Form
function LoginForm() {
const { values, handleChange, resetForm } = useForm({ email: "", password: "" });
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted:", values);
resetForm();
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
value={values.email}
onChange={handleChange}
placeholder="Email"
/>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}
Any new form (signup, profile update, contact form) can now reuse this same useForm
hook.
Key Takeaways
Custom hooks let you encapsulate logic and reuse it across components.
They make your code cleaner, modular, and easier to maintain.
-
Use them for tasks like:
- Fetching data
- Form handling
- Authentication checks
- Managing browser events (scroll, resize, etc.)
Ending Notes
Custom hooks are not some advanced React trick they’re just functions. But when used wisely, they can dramatically improve your code quality and development speed.
Next time you find yourself copy-pasting hook logic, stop and think:
“Can I move this into a custom hook?”
Chances are, the answer is yes and your future self will thank you.
Top comments (0)