Abort fetch

2 snippets across 2 stacks — JavaScript, React

JSJavaScript

AbortController

JS · Async Programming
syntax
const controller = new AbortController();
fetch(url, { signal: controller.signal });
controller.abort();
example
async function searchWithCancel(query) {
  const controller = new AbortController();

  // Auto-cancel after 5 seconds
  const timeoutId = setTimeout(() => controller.abort(), 5000);

  try {
    const res = await fetch(`/api/search?q=${query}`, {
      signal: controller.signal,
    });
    clearTimeout(timeoutId);
    return await res.json();
  } catch (err) {
    if (err.name === "AbortError") {
      console.log("Request was cancelled");
    } else {
      throw err;
    }
  }
}

Note Essential for cancelling stale requests (e.g., in search-as-you-type). The AbortSignal can be shared across multiple fetch calls to cancel them all at once.

REReact

Setting State After Unmount

RE · Common Mistakes
syntax
// PROBLEM: async callback sets state on unmounted component
useEffect(() => {
  fetchData().then(data => setState(data)); // may be unmounted!
}, []);

// FIX: track mounted status
useEffect(() => {
  let active = true;
  fetchData().then(data => { if (active) setState(data); });
  return () => { active = false; };
}, []);
example
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    let cancelled = false;

    async function loadUser() {
      const response = await fetch(`/api/users/${userId}`);
      const data = await response.json();

      // Only update state if this effect is still active
      if (!cancelled) {
        setUser(data);
      }
    }

    loadUser();

    return () => {
      cancelled = true;
    };
  }, [userId]);

  if (!user) return <p>Loading...</p>;
  return <h1>{user.name}</h1>;
}

Note While React 18+ no longer warns about this, it is still a logic bug. Without the cancelled flag, a slow request for user A could resolve after switching to user B, overwriting user B's data with user A's data. Always use a cleanup flag or AbortController.