Skip to content

fix: useattendance races #3854

Open
ionfwsrijan wants to merge 4 commits into
Premshaw23:masterfrom
ionfwsrijan:fix/useattendance-races-3851
Open

fix: useattendance races #3854
ionfwsrijan wants to merge 4 commits into
Premshaw23:masterfrom
ionfwsrijan:fix/useattendance-races-3851

Conversation

@ionfwsrijan

Copy link
Copy Markdown
Contributor

Summary

Multiple async fetchers in useAttendance could call setState after the component
unmounted (or after a re-render with different deps), causing React state-update warnings
and stale data display. The fetchGamification callback had a broken AbortController
pattern — the controller was created inside the callback but never accessible to the
effect's cleanup function.

Changes

hooks/useAttendance.js

  • All async fetchers (fetchStudentActivity, fetchGamification,
    fetchTodayAttendanceStats, loadMoreRequests) now accept an optional
    AbortSignal parameter and check signal.aborted before calling setState

  • Student effect: creates a single AbortController, passes its signal to both
    fetchers, and calls controller.abort() in the cleanup

  • Teacher stats effect: same pattern — AbortController created in the effect,
    passed to fetchTodayAttendanceStats, aborted on cleanup

  • fetchGamification: removed the broken internal AbortController / return
    of cleanup function from useCallback (React ignores the return value of
    callbacks); controller ownership moved to the effect

  • fetchTodayAttendanceStats: added signal?.aborted guard before setAttendanceStats

  • loadMoreRequests: passes signal to apiFetch, guards setAttendanceRequests,
    and avoids resetting loadingRequests when aborted

  • All catch blocks now check for AbortError and skip error logging when the
    fetch was intentionally cancelled

    Closes [Bug] Race Conditions in useAttendance Hook: Stale State Overwrites, Duplicate Firestore Queries Bypassing Pool, and Data Inconsistency Window #3851

opencode-bot added 4 commits June 23, 2026 13:56
- Create lib/api-routes-config.js as the single source of truth
- Includes missing /api/upload/certificate and /api/achievements rules
- rbac-policy.js re-exports from shared config
- rbac.js imports from shared config instead of rbac-policy
- middleware.js imports from shared config, removing inline definitions
…jections

- Import getAuth from firebase/auth (was missing, causing ReferenceError)
- Replace getOutboxRecords with getPendingActions (already imported from offlineStore)
- Replace removeFromOutbox with removePendingAction (already imported from offlineStore)
- Wrap module-level window.addEventListener('online') in setupNetworkListener()
  with explicit cleanup function; register HMR dispose hook to prevent leak
- Attach .catch() handlers to unhandled syncAttendanceQueue() promise
  in registerBackgroundSync fallback paths
- Pass AbortController signals through all async fetchers
  and check signal.aborted before setState calls
- Fix broken AbortController pattern in fetchGamification
  (controller was created inside callback but never accessible
  to the effect's cleanup; now created in the effect and passed in)
- Add stale-guard checks to fetchStudentActivity, fetchTodayAttendanceStats,
  and loadMoreRequests to prevent setState after unmount
- Handle AbortError gracefully in all fetch paths
- Ensure loadingRequests is not reset if the request was aborted
@ionfwsrijan

Copy link
Copy Markdown
Contributor Author

@Premshaw23 Please review this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Race Conditions in useAttendance Hook: Stale State Overwrites, Duplicate Firestore Queries Bypassing Pool, and Data Inconsistency Window

1 participant