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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs