JAVASCRIPT
Build a Custom useFetch Hook for Data Retrieval
Create a reusable `useFetch` custom hook in React to handle asynchronous data fetching, managing loading, error, and data states efficiently.
import { useState, useEffect } from 'react';
// Custom useFetch Hook
function useFetch(url, options) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
async function fetchData() {
setLoading(true);
setError(null);
try {
const response = await fetch(url, { ...options, signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (err) {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
return; // Do not set error if fetch was intentionally aborted
}
setError(err);
} finally {
setLoading(false);
}
}
if (url) {
fetchData();
}
// Cleanup function to abort fetch request if component unmounts or URL changes
return () => {
abortController.abort();
};
}, [url, JSON.stringify(options)]); // Dependency array: re-fetch if URL or options change
return { data, loading, error };
}
// Example Component using useFetch
function UserProfileFetcher() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users/1');
if (loading) return <p>Loading user profile...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!data) return <p>No user data found.</p>;
return (
<div>
<h2>User Profile</h2>
<p>Name: {data.name}</p>
<p>Email: {data.email}</p>
<p>Website: {data.website}</p>
</div>
);
}
export default UserProfileFetcher;
How it works: The `useFetch` custom hook encapsulates the logic for fetching data from a given URL. It manages three states: `data` (the fetched data), `loading` (a boolean indicating if a fetch is in progress), and `error` (any error encountered). Inside a `useEffect`, an asynchronous `fetchData` function is defined to handle the API call, including error checking and JSON parsing. An `AbortController` is used to cancel pending fetch requests if the component unmounts or the URL/options dependencies change, preventing memory leaks and stale state updates. The hook returns these three states, making it easy for components to consume.