Skip to content

fix(frontend): race conditions, memory leaks in 4 hooks + pin GitHub Actions to commit SHAs - #1291

Merged
leojay-net merged 3 commits into
leojay-net:mainfrom
christianahtemitope2005:fix/issues-1213-1215-1217-1219
Jul 27, 2026
Merged

fix(frontend): race conditions, memory leaks in 4 hooks + pin GitHub Actions to commit SHAs#1291
leojay-net merged 3 commits into
leojay-net:mainfrom
christianahtemitope2005:fix/issues-1213-1215-1217-1219

Conversation

@christianahtemitope2005

@christianahtemitope2005 christianahtemitope2005 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Root causes and fixes

#1213useChatHistory.ts: stale-closure race condition

updateCurrentSession read historyState.currentSessionId from a stale closure. Fix: moved guard inside the functional updater. loadSession + 5 other callbacks read stale historyState.sessions. Fix: sessionsRef kept current, all read-only callbacks use sessionsRef.current. Regression tests added.

#1215useChatPerformance.ts: stale start-time

startTimeRef only set on mount → render time was always time-since-mount. Fix: capture startTime per-effect-run. Added isMountedRef guard.

#1217useCurrencyConversion.ts: async setState after unmount (memory leak)

setState fired after unmount when fetch resolved. Fix: isMountedRef checked after every await and in finally. Regression test added.

#1219useEffectiveDarkMode.ts: untracked DOM subscription

Synchronous document.documentElement.getAttribute during render caused SSR mismatch and never reacted to data-theme changes post-mount. Fix: MutationObserver with disconnect() cleanup.

#1268 — Pin GitHub Actions to commit SHAs

Action Tag SHA
actions/checkout v4 11d5960
actions/setup-node v4 49933ea
actions/cache v4 0057852
actions/upload-artifact v4 ea165f8
actions/github-script v7 f28e40c
pnpm/action-setup v4 f40ffcd
Swatinem/rust-cache v2 42dc69e
stefanzweifel/git-auto-commit-action v5 b863ae1
dtolnay/rust-toolchain stable 2c7215f

Closes #1213, Closes #1215, Closes #1217, Closes #1219, Closes #1268

…nd memory leaks in useCurrencyConversion/useEffectiveDarkMode

Root causes and fixes:

leojay-net#1213 — useChatHistory.ts: stale-closure race condition
  updateCurrentSession read `historyState.currentSessionId` from the closure
  captured at useCallback creation. If a session switch landed between renders
  the guard could be stale: either blocking a valid update or targeting the
  wrong session. Fix: moved the null-check inside the functional updater so it
  always sees the latest committed state.

  loadSession, exportSession, exportSessionAsJSON, exportSessionAsTXT,
  searchSessions, and getCurrentSession all read `historyState.sessions`
  directly from their closures — a stale snapshot whenever rapid state updates
  were in-flight. Fix: added a sessionsRef kept current via useEffect and
  switched all read-only callbacks to read from sessionsRef.current.

  Regression tests added to useChatHistory.test.ts covering:
  - updater is a no-op when currentSessionId is null in latest state
  - updater targets the session from latest state, not the closure snapshot
  - loadSession finds sessions added after the callback was captured

leojay-net#1215 — useChatPerformance.ts: stale startTime causes wrong render-time metric
  startTimeRef was set only in a mount-only effect (empty deps), so
  renderTimeRef always measured time-since-mount rather than time-since-last
  messages.length change. Fix: capture startTime at the top of each
  messages.length effect run. Added isMountedRef guard to prevent ref/log
  writes after unmount.

leojay-net#1217 — useCurrencyConversion.ts: async setState after unmount (memory leak)
  fetchCryptoPrices is async. When the component unmounted while a fetch was
  in-flight, setState was still called on resolution, leaking the closure and
  triggering React's "state update on unmounted component" warning. Fix: added
  isMountedRef; every setState call is guarded by isMountedRef.current checks
  both after await and in the finally block.

  Regression test added to useCurrencyConversion.test.tsx: unmounts the hook
  before the mock fetch resolves, then resolves it, and asserts console.error
  is not called with an "unmounted" warning.

leojay-net#1219 — useEffectiveDarkMode.ts: untracked DOM subscription + SSR mismatch
  document.documentElement.getAttribute('data-theme') was called synchronously
  during render on every re-render, causing SSR/client hydration mismatches and
  never reacting to data-theme changes that happened after mount. Fix: replaced
  the synchronous DOM read with a MutationObserver scoped to <html>'s
  attribute changes; observer.disconnect() is called in the effect cleanup,
  fully closing the subscription on unmount.

Closes leojay-net#1213, Closes leojay-net#1215, Closes leojay-net#1217, Closes leojay-net#1219
Replace mutable tags with immutable commit SHAs so a compromised or
retagged upstream release cannot execute arbitrary code with repo write
permissions. Version tags preserved as inline comments for readability.

- actions/checkout          v4  → 11d5960
- actions/setup-node        v4  → 49933ea
- actions/cache             v4  → 0057852
- actions/upload-artifact   v4  → ea165f8
- actions/github-script     v7  → f28e40c
- pnpm/action-setup         v4  → f40ffcd
- Swatinem/rust-cache       v2  → 42dc69e
- stefanzweifel/git-auto-commit-action v5 → b863ae1
- dtolnay/rust-toolchain    stable → 2c7215f

Closes leojay-net#1268
@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@christianahtemitope2005 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@christianahtemitope2005 christianahtemitope2005 changed the title fix(frontend): race conditions in useChatHistory/useChatPerformance and memory leaks in useCurrencyConversion/useEffectiveDarkMode fix(frontend): race conditions, memory leaks in 4 hooks + pin GitHub Actions to commit SHAs Jul 27, 2026
@leojay-net
leojay-net merged commit 4719ed4 into leojay-net:main Jul 27, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment