JAVASCRIPT
useFetch Hook for Asynchronous Data Fetching
Develop a reusable `useFetch` React hook to manage data fetching, including loading, error, and data states, simplifying API integrations in components.
import { useState, useEffect } from 'react';
const 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);
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
};
fetchData();
}, [url, JSON.stringify(options)]); // Deep comparison for options is a common workaround, but can be inefficient for large objects. For production, consider using a custom deep-equality comparison hook or `useMemo` for options if they are complex objects.
return { data, loading, error };
};
// Example Usage:
// import React from 'react';
// function UserProfile({ userId }) {
// const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
//
// if (loading) return <p>Loading user data...</p>;
// if (error) return <p>Error: {error.message}</p>;
// if (!user) return <p>No user data found.</p>;
//
// return (
// <div>
// <h2>{user.name}</h2>
// <p>Email: {user.email}</p>
// </div>
// );
// }
How it works: The `useFetch` hook encapsulates the logic for making an asynchronous data request. It maintains `data`, `loading`, and `error` states, which are returned to the consuming component. When the `url` or `options` dependencies change, `useEffect` triggers the `fetchData` function, which handles the API call, parses the response, and updates the respective states. This pattern provides a clean, reusable way to manage the lifecycle of data fetching in React applications.