Files
BanGUI/frontend/src/hooks/README.md
Lukas 3bd2a71367 Refactor usePolledData hook and add comprehensive tests
- Renamed usePolledIntervalCheck to usePolledData for clarity
- Updated hook to properly manage interval cleanup on unmount
- Added comprehensive test suite covering normal operation, error handling, and cleanup
- Updated documentation to reflect new hook name
- Updated Tasks.md to track progress

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 20:24:47 +02:00

56 lines
2.3 KiB
Markdown

# 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