Files
BanGUI/frontend/src/hooks
Lukas 3b3728c58d feat: implement request deduplication in useFetchData
- Add optional requestKey parameter to UseFetchDataOptions
- Implement module-level cache (inFlightRequests) to track in-flight requests
- When requestKey is provided, multiple hook instances with same key share in-flight requests
- Prevents duplicate API calls when multiple components fetch same data or rapid refresh calls
- Cache entries are automatically cleared when response arrives (success or error)
- Maintains backward compatibility: without requestKey, behaves as before
- Adds comprehensive tests for deduplication scenarios

This reduces bandwidth waste and prevents race conditions caused by concurrent requests for identical data.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 18:44:46 +02:00
..

React Hook Fetch Cancellation

This folder follows a shared convention for network fetch cancellation in React hooks.

Patterns

1. Hooks with manual refresh

Hooks that expose a refresh() callback must use a long-lived AbortController stored in a ref:

  • `const abortRef = useRef<AbortController | null>(null);
  • Call abortRef.current?.abort() before starting a new request.
  • Create a fresh controller before every refresh() invocation.
  • Pass controller.signal to the API function.
  • In the cleanup effect, abort the controller when the hook unmounts.
  • After each await, check signal.aborted before updating state.

This prevents stale responses from overwriting newer results and avoids React state updates after unmount.

2. One-shot mount-only requests

Hooks that only fetch once inside useEffect and do not expose a manual refresh may use a local controller:

  • Create const controller = new AbortController(); inside the effect.
  • Pass controller.signal to the request.
  • Abort it in the effect cleanup.
  • This is the simplest correct pattern for single-fetch hooks.

3. Do not use boolean cancelled flags for network requests

A boolean cancelled flag is not sufficient because it does not stop the underlying fetch. Abort signals are the correct cancellation mechanism for fetch-based hooks.

Polling with Drift Correction

The usePolledData hook implements drift-corrected polling to maintain accurate polling intervals despite variable fetch durations.

How it works

  • Uses self-scheduling timeouts instead of fixed setInterval
  • Tracks elapsed time from poll start to completion with performance.now()
  • Calculates next delay as Math.max(0, pollInterval - elapsed)
  • Schedules the next poll with drift compensation in the onSuccess callback
  • If a fetch takes longer than pollInterval, the next poll starts immediately (delay = 0)

Why this matters

With fixed setInterval:

  • If a fetch takes 2 seconds and pollInterval is 5 seconds
  • Actual polling interval becomes ~7 seconds (2s fetch + 5s interval)
  • Effective polling rate drifts and wastes bandwidth

With drift correction:

  • Total time from poll start to next poll start is always ~5 seconds
  • Fetch duration doesn't affect the long-term polling rate
  • Bandwidth and CPU usage remain consistent