JAVASCRIPT

`useFetchWithAbort` for Cancellable Data Fetching

Create a `useFetchWithAbort` React hook to perform data fetching with built-in `AbortController` support, enabling request cancellation for improved UX.

import { useState, useEffect, useRef } from 'react';

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

  useEffect(() => {
    abortControllerRef.current = new AbortController();
    const signal = abortControllerRef.current.signal;

    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(url, { ...options, signal });
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        if (err.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      // Abort the fetch request if the component unmounts or dependencies change
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
      }
    };
  }, [url, JSON.stringify(options)]); // Dependency on options needs careful handling or deep comparison

  // Manual abort function (optional)
  const abort = () => {
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
      console.log('Manually aborted fetch');
    }
  };

  return { data, loading, error, abort };
}

// Example Usage:
/*
function UserProfile({ userId }) {
  const { data: user, loading, error, abort } = useFetchWithAbort(
    `https://jsonplaceholder.typicode.com/users/${userId}`
  );

  if (loading) return <div>Loading user...</div>;
  if (error) return <div>Error: {error.message} <button onClick={abort}>Cancel Fetch</button></div>;
  if (!user) return null;

  return (
    <div>
      <h2>User Profile</h2>
      <p>Name: {user.name}</p>
      <p>Email: {user.email}</p>
      <button onClick={abort}>Abort Current Request</button>
    </div>
  );
}
*/
How it works: The `useFetchWithAbort` hook facilitates data fetching while allowing requests to be cancelled using `AbortController`. It manages `data`, `loading`, and `error` states. A new `AbortController` is created with each fetch. If the component unmounts or the `url`/`options` dependencies change before the fetch completes, the cleanup function aborts the ongoing request, preventing memory leaks and unnecessary state updates. It also exposes an `abort` function for manual cancellation.

Need help integrating this into your project?

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

Hire DigitalCodeLabs