JAVASCRIPT
Build a Generic Data Fetching useFetch Custom Hook
Create a versatile `useFetch` custom hook in React for handling data fetching, including loading and error states. Simplify API calls across your application.
import { useState, useEffect } from 'react';
function useFetch(url, options) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
setError(null); // Reset error on new fetch attempt
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (fetchError) {
setError(fetchError);
} finally {
setLoading(false);
}
};
if (url) { // Only fetch if URL is provided
fetchData();
}
// Cleanup function (optional, but good practice for aborting requests)
// const abortController = new AbortController();
// options = { ...options, signal: abortController.signal };
// return () => abortController.abort(); // Abort fetch on unmount
}, [url, JSON.stringify(options)]); // Re-run if URL or options change
return { data, loading, error };
}
// Example usage:
function PostsComponent() {
const { data: posts, loading, error } = useFetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
// For a POST request, you might pass options like:
// const { data: postResult } = useFetch('https://jsonplaceholder.typicode.com/posts', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ title: 'foo', body: 'bar', userId: 1 }),
// });
if (loading) return <p>Loading posts...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!posts) return <p>No posts found.</p>;
return (
<div>
<h2>Latest Posts</h2>
<ul>
{posts.map((post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</li>
))}
</ul>
</div>
);
}
export default PostsComponent;
How it works: The `useFetch` custom hook provides a streamlined way to handle asynchronous data fetching in React components. It manages three key pieces of state: `data` (for the fetched result), `loading` (to indicate ongoing requests), and `error` (for any issues during fetching). The `useEffect` hook performs the actual `fetch` operation, updating these states accordingly. It takes a `url` and optional `options` (like method, headers, body) for the `fetch` API, re-running the fetch whenever these dependencies change. This hook simplifies displaying UI based on the fetch status.