[React.js] - Part 16. React Hooks - Custom Hook

Ace Lennox
React Custom Hooks are a powerful way to reuse logic across multiple components. By extracting common functionality into reusable functions, you can keep your code DRY (Don’t Repeat Yourself) and maintainable. In this guide, we’ll learn how to create and use custom Hooks with easy-to-follow examples.
What Are Custom Hooks?
Custom Hooks are reusable functions in React that encapsulate component logic. They always start with the prefix use
, such as useFetch
, and can include state, effects, or any other Hook logic.
Why Use Custom Hooks?
Reusability: Share logic between multiple components.
Cleaner Code: Move complex logic out of components for better readability.
Consistency: Standardize common patterns across your app.
Example 1: Fetching Data Without a Custom Hook
Here’s an example where a Home
component fetches and displays data:
index.js
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
const Home = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => response.json())
.then((data) => setData(data));
}, []);
return (
<div>
<h2>Posts</h2>
{data &&
data.map((post) => (
<p key={post.id}>{post.title}</p>
))}
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Home />);
What’s the Issue?
If you need to fetch data in another component, you’ll have to duplicate this logic. This violates the DRY principle and makes your code harder to maintain.
Example 2: Creating a Custom Hook
We’ll extract the fetch logic into a reusable custom Hook called useFetch
.
useFetch.js
import { useState, useEffect } from "react";
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading };
};
export default useFetch;
Explanation
Reusable Logic: The
useFetch
Hook takes a URL as a parameter and returns the fetched data and loading state.Async/Await: Improved readability for asynchronous operations.
Error Handling: Handles errors gracefully.
Example 3: Using the Custom Hook
Now we’ll use useFetch
in the Home
component.
index.js
import ReactDOM from "react-dom/client";
import useFetch from "./useFetch";
const Home = () => {
const { data, loading } = useFetch("https://jsonplaceholder.typicode.com/posts");
if (loading) {
return <h2>Loading...</h2>;
}
return (
<div>
<h2>Posts</h2>
{data &&
data.map((post) => (
<p key={post.id}>{post.title}</p>
))}
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Home />);
Key Improvements
Simpler Component: The
Home
component is now focused only on rendering UI.Reusable Hook: The fetch logic can now be reused in any component by simply calling
useFetch
.Scalability: Adding more features to the Hook (e.g., caching or error messages) will benefit all components that use it.
Benefits of Custom Hooks
Encapsulation: Separate logic from UI.
Reusability: Use the same logic across multiple components.
Scalability: Easily add more functionality to your Hooks.
Best Practices
Prefix with
use
: Always start custom Hooks withuse
to follow React conventions.Avoid Side Effects: Keep Hooks pure and avoid side effects inside them.
Document Usage: Clearly define what parameters the Hook accepts and what it returns.
Test Thoroughly: Ensure your Hooks handle edge cases, like errors or loading states.
Conclusion
Custom Hooks are a powerful tool in React for organizing and reusing logic. By extracting shared logic into Hooks, you can make your components cleaner, more modular, and easier to maintain.
Try building your own custom Hooks to see how they can simplify your React projects!
Source Code
The complete source code for this part is available on GitHub