Blog>
Snippets

Creating a Custom Hook for Fetching Data

Demonstrate how to create a custom React hook that encapsulates data fetching logic, providing reusability and cleaner components.
import { useState, useEffect } from 'react';

// This is our custom hook for fetching data
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error(response.statusText);
        const data = await response.json();
        setData(data);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;
The 'useFetch' function is a custom hook that encapsulates the logic for fetching data from a specified URL. It uses useState to manage the data, loading state, and any errors encountered during fetching. The useEffect hook triggers the data retrieval process when the URL changes. The fetchData asynchronous function within useEffect handles the actual API call, error handling, and state updates. Then, the hook returns the current state of the data, loading, and error so components can use these in their render logic.
import React from 'react';
import useFetch from './useFetch'; // Importing our custom hook

function DataComponent({ dataSource }) {
  const { data, loading, error } = useFetch(dataSource);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Data</h1>
      {/* We can directly use 'data' here because our hook has already fetched and prepared it. */}
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}
This DataComponent utilizes our custom hook 'useFetch' by passing a 'dataSource' URL prop to it. The component destructures the 'data', 'loading', and 'error' from the hook and uses these to conditionally render the appropriate UI feedback. If the data is still loading, it displays a loading message. If an error occurs during fetching, it displays the error. Else, it presents the fetched data.