JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeQuestionsreact
PrevNext

Learn the concept

Hooks

react
mid
custom-hooks

How would you implement a useFetch custom hook?

custom-hooks
data-fetching
hooks
abort-controller
async
Quick Answer

A useFetch hook encapsulates data fetching logic with loading, error, and data states. It uses AbortController to handle cleanup and race conditions when the URL changes or the component unmounts, and can support refetch and basic caching.

Detailed Explanation

Why useFetch:

  • Eliminates repeated fetch boilerplate across components
  • Standardizes loading, error, and data state management
  • Properly handles race conditions that are easy to get wrong with raw useEffect
  • Provides a foundation for understanding how libraries like TanStack Query work

Core Implementation:

  1. Accept a URL (and optional config) as parameters
  2. Manage three pieces of state: data, error, loading
  3. Use useEffect to trigger the fetch when the URL changes
  4. Use AbortController to cancel in-flight requests on cleanup
  5. Return { data, error, loading } and optionally a refetch function

Race Condition Handling:

  • When the URL changes rapidly, multiple requests may be in flight
  • Without AbortController, an earlier request could resolve after a later one
  • AbortController cancels the previous request, ensuring only the latest response is used
  • The AbortError must be caught and ignored (it is expected behavior)

Refetch Capability:

  • Expose a refetch function that re-triggers the fetch imperatively
  • Useful after mutations (create, update, delete) to refresh data
  • Can be implemented by toggling a counter state in the dependency array

Comparison with Libraries:

  • TanStack Query: Adds caching, pagination, optimistic updates, devtools, automatic retries
  • SWR: Lightweight stale-while-revalidate with revalidation strategies
  • React 19 use(): Built-in promise support with Suspense, but no caching or retry logic
  • A custom useFetch is great for learning and simple cases; use a library for production apps

Code Examples

Basic useFetch with AbortControllerJavaScript
import { useState, useEffect } from 'react';

function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!url) {
      setData(null);
      setLoading(false);
      return;
    }

    const controller = new AbortController();

    async function fetchData() {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch(url, {
          ...options,
          signal: controller.signal,
        });

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }

        const json = await response.json();
        setData(json);
      } catch (err) {
        // Ignore abort errors — they are expected on cleanup
        if (err.name !== 'AbortError') {
          setError(err);
        }
      } finally {
        if (!controller.signal.aborted) {
          setLoading(false);
        }
      }
    }

    fetchData();

    // Cleanup: abort fetch on unmount or URL change
    return () => controller.abort();
  }, [url]);

  return { data, error, loading };
}

Real-World Applications

Use Cases

Dashboard Data Loading

Fetching multiple API endpoints to populate dashboard widgets, with each widget independently showing loading and error states

Infinite Scroll / Pagination

Fetching paginated data as the user scrolls, using useFetch with a dynamic URL that includes the current page or cursor parameter

Feature Flags Loading

Fetching remote feature flag configuration on app startup, with the hook managing the loading state while the flags are resolved

Mini Projects

GitHub Repository Explorer

intermediate

Build a React app that uses useFetch to search GitHub repositories by username with pagination and proper race condition handling

useFetch with SWR Caching

advanced

Extend useFetch to implement stale-while-revalidate: serve cached data instantly while fetching fresh data in the background

Industry Examples

TanStack Query

Builds on the useFetch concept with a production-grade solution adding caching, deduplication, pagination, optimistic updates, and background refetching

SWR (Vercel)

Implements the stale-while-revalidate pattern as a React hook, inspired by the same data-fetching patterns that useFetch demonstrates

Resources

React Docs - Reusing Logic with Custom Hooks

docs

TanStack Query Documentation

docs

MDN - AbortController

docs

Related Questions

Explain the useState and useEffect hooks and their common patterns.

mid
hooks
Previous
How would you implement a useLocalStorage custom hook?
Next
What are the differences between CSR, SSR, and SSG in React applications?
PrevNext