Skip to content

refactor: eliminate unnecessary useEffects — bridges, effect events, budget ratchet (E1–E3, E7) - #163

Open
TheOrcDev wants to merge 1 commit into
mainfrom
refactor/effect-elimination
Open

refactor: eliminate unnecessary useEffects — bridges, effect events, budget ratchet (E1–E3, E7)#163
TheOrcDev wants to merge 1 commit into
mainfrom
refactor/effect-elimination

Conversation

@TheOrcDev

Copy link
Copy Markdown
Owner

Executes the first tranche of the useEffect elimination plan (follow-up to franky47's #150 review). use-studio.tsx: 58 → 48 effects; renderer total 108, now enforced by a ratchet. Zero behavior changes.

What changed

E1 — mirrors + persistence. Latest-value ref mirrors (deviceListRef, captureConfigRef) become render-body assignments — the pattern the file already used for settingsRef. localStorage persistence moves to a LocalStoragePersister bridge: object-identity fast path (re-renders are free), content dedupe, 150ms trailing debounce, pagehide flush, and explicit quota-failure diagnostics. The old effects JSON-serialized the full captureConfig synchronously on every change.

E2 — real subscription bugs. The window keydown listener listed ten callback identities in its deps, so it removed/re-added itself on practically every session-state render; the comment-highlight IPC listener resubscribed on every chat message. Every swap was a window where a shortcut or highlight request could drop. Both are now useEffectEvent handlers with one mount-only registration; the two comment IPC listeners share a single effect.

E3 — transition logic lives with the transition. The X Producer reminder runs from applyRecordingStatus (the single recording-state funnel); failed-stream-target toasts run from the streamTargets mutation sites, driven by the snapshot the backend just delivered.

E4-lite — one-way pushes. A generic RenderSyncedCall<T> bridge (content dedupe, post-commit send, unit-tested) replaces the preview-aspect-ratio and captions-window-snapshot effects. The orientation integration test now awaits the bridge tick — the asserted contract (the new dimensions arrive, never stale ones) is unchanged.

E7 — the ratchet. scripts/check-effect-budget.mjs is wired into pnpm lint: per-file budgets (checked in at today's reality, 108 across 34 files) fail on any increase, and a file that improves fails until the budget is ratcheted down — wins get locked in, and the count can never silently grow again.

Verification

  • Desktop suite 1206 green, including all 29 studio-provider integration tests (the recording-spine safety net for this file), plus new unit tests for both bridges.
  • pnpm typecheck, pnpm lint (now including the budget gate), pnpm format:check, pnpm test:scripts (759) all green.
  • smoke:remote-control could not be exercised: the dev-app launcher times out on clean main too (Electron starts, zero output, no [smoke] markers) — pre-existing after perf: bound runtime and Studio resource lifetimes #153/feat: add secure Windows alpha release pipeline #154, tracked as a separate task; not caused by this branch.

Remaining plan slices (follow-ups, pinned by the ratchet)

E3 remainder (mic-meter reset, caption epochs, platform-account refreshes), E4 heavy bridges (LiveAudioMirror, CaptionAppearanceMirror, StreamKeyHintHydrator), E5 WindowStateReconciler, E6 component tail sweep. Each is a separate reviewable PR per the plan's non-negotiables.

🤖 Generated with Claude Code

…atchet)

use-studio.tsx drops from 58 to 48 useEffects with zero behavior changes;
franky47's PR #150 review generalized (vault plan 2026-07-19).

E1 — latest-value ref mirrors become render-body assignments (the file's
existing settingsRef pattern); the client-reset of the layout-commit proof
moves into the client-setup effect; localStorage persistence rides a new
LocalStoragePersister bridge (identity fast path so renders are free,
content dedupe, 150ms trailing debounce, pagehide flush, explicit quota
diagnostics) instead of two serialize-on-every-change effects.

E2 — subscription churn bugs fixed with React 19.2 effect events: the
window keydown listener re-registered on TEN callback identities
(practically every session-state render) and the comment-highlight IPC
listener resubscribed on every chat message — each swap a window where an
event could drop. Both handlers are now useEffectEvent with ONE mount-only
registration; the two comment IPC listeners share a single effect.

E3 — state-transition reactions move into the handlers that apply the
transition: the X Producer reminder runs from applyRecordingStatus, and
failed-stream-target toasts run from the streamTargets mutation sites
(snapshot-driven, empty snapshot resets the dedupe).

E4-lite — one-way pushes ride a generic RenderSyncedCall bridge (content
dedupe, post-commit send): preview-window aspect ratio and the captions
window snapshot. The orientation integration test now awaits the bridge
tick; the contract (new dimensions arrive, never stale ones) is unchanged
and still asserted.

E7 — scripts/check-effect-budget.mjs ratchet wired into pnpm lint: per-file
useEffect budgets (108 across 34 renderer files) fail the gate on ANY
increase and demand a ratchet-down when a file improves, so the count can
never silently grow again.

Verification: desktop 1206 green incl. all 29 studio-provider integration
tests, new persister/bridge unit tests, typecheck, lint + budget gate,
format, scripts 759 green. smoke:remote-control could not run: the dev-app
launcher times out on CLEAN main too (no [smoke] markers after "start
electron app") — pre-existing, tracked separately.

Remaining plan slices (E3 rest, E4 heavy bridges, E5 window reconciler,
E6 component tail) are follow-ups; the ratchet pins today's counts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@TheOrcDev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 6 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f56c826-17ef-4c85-9be4-17eb4d532beb

📥 Commits

Reviewing files that changed from the base of the PR and between 8293271 and 6a5f8ba.

📒 Files selected for processing (9)
  • apps/desktop/src/renderer/src/hooks/studio-provider.integration.test.ts
  • apps/desktop/src/renderer/src/hooks/use-studio.tsx
  • apps/desktop/src/renderer/src/lib/local-storage-persister.test.ts
  • apps/desktop/src/renderer/src/lib/local-storage-persister.ts
  • apps/desktop/src/renderer/src/lib/render-synced-call.test.ts
  • apps/desktop/src/renderer/src/lib/render-synced-call.ts
  • package.json
  • scripts/check-effect-budget.mjs
  • scripts/effect-budget.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/effect-elimination

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

1 participant