- 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>
56 lines
2.3 KiB
Markdown
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
|