fix(frontend): race conditions, memory leaks in 4 hooks + pin GitHub Actions to commit SHAs - #1291
Merged
leojay-net merged 3 commits intoJul 27, 2026
Conversation
…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
|
@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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root causes and fixes
#1213 —
useChatHistory.ts: stale-closure race conditionupdateCurrentSessionreadhistoryState.currentSessionIdfrom a stale closure. Fix: moved guard inside the functional updater.loadSession+ 5 other callbacks read stalehistoryState.sessions. Fix:sessionsRefkept current, all read-only callbacks usesessionsRef.current. Regression tests added.#1215 —
useChatPerformance.ts: stale start-timestartTimeRefonly set on mount → render time was always time-since-mount. Fix: capturestartTimeper-effect-run. AddedisMountedRefguard.#1217 —
useCurrencyConversion.ts: async setState after unmount (memory leak)setStatefired after unmount when fetch resolved. Fix:isMountedRefchecked after everyawaitand infinally. Regression test added.#1219 —
useEffectiveDarkMode.ts: untracked DOM subscriptionSynchronous
document.documentElement.getAttributeduring render caused SSR mismatch and never reacted todata-themechanges post-mount. Fix:MutationObserverwithdisconnect()cleanup.#1268 — Pin GitHub Actions to commit SHAs
actions/checkout11d5960actions/setup-node49933eaactions/cache0057852actions/upload-artifactea165f8actions/github-scriptf28e40cpnpm/action-setupf40ffcdSwatinem/rust-cache42dc69estefanzweifel/git-auto-commit-actionb863ae1dtolnay/rust-toolchain2c7215fCloses #1213, Closes #1215, Closes #1217, Closes #1219, Closes #1268