Files
BanGUI/frontend/src/hooks/useNavigationAbortSignal.ts
Lukas 7ba1cf7ca2 feat: Implement global request lifecycle cancellation on route transitions
Adds a navigation-aware request cancellation mechanism that automatically
aborts all route-specific API requests when the user navigates to a
different route. This prevents silent state-update errors from responses
arriving after component unmount and conserves bandwidth by cancelling
now-irrelevant requests.

Key additions:
- NavigationCancellationContext: Context for managing route-specific signals
- NavigationCancellationProvider: Provider that detects route changes and
  aborts all signals from the previous route
- useNavigationAbortSignal hook: Allows components to subscribe to
  navigation-aware cancellation signals
- Comprehensive tests for the cancellation lifecycle
- Documentation in Web-Development.md for request lifecycle policy

The provider is placed in the app hierarchy between BrowserRouter and
AuthProvider, ensuring consistent cancellation behavior across all routes.

Long-lived background tasks (polling, session validation) can opt-out by
managing their own AbortController lifecycle.

Closes #23 from Tasks.md: No global cancellation policy on route transitions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-28 09:58:59 +02:00

54 lines
1.9 KiB
TypeScript

/**
* Hook to subscribe to navigation-aware request cancellation.
*
* Returns an AbortSignal that is automatically aborted when the user
* navigates to a different route. Use this signal to cancel API requests
* that are specific to the current route and should not survive a navigation.
*
* Usage:
* const signal = useNavigationAbortSignal();
* const { items } = useListData({
* fetcher: (sig) => fetchBans(sig || signal),
* // ...
* });
*
* When to use:
* - For page-level data fetches that should not persist across navigation
* - For user-initiated refetches on the current page
* - For paginated lists, search results, filters
*
* When NOT to use:
* - For long-lived background polls (use your own AbortController instead)
* - For service-level state syncs (e.g., session validation)
* - For actions that may take longer than a user interaction timeout
*
* Note: The signal may already be aborted at the time you check it,
* depending on timing. This is safe — fetchers should handle aborted
* signals gracefully by throwing/catching AbortError.
*/
import { useContext } from "react";
import { NavigationCancellationContext } from "../providers/NavigationCancellationContext";
/**
* Get an AbortSignal for the current route's request lifecycle.
*
* The returned signal will be aborted when the user navigates away.
* All requests using this signal will be automatically cancelled.
*
* @returns AbortSignal tied to the current route
* @throws Error if called outside NavigationCancellationProvider
*/
export function useNavigationAbortSignal(): AbortSignal {
const context = useContext(NavigationCancellationContext);
if (!context) {
throw new Error(
"useNavigationAbortSignal must be used within NavigationCancellationProvider. " +
"Wrap your router with <NavigationCancellationProvider> in App.tsx.",
);
}
return context.getNavigationSignal();
}