Skip to content

chore(web): upgrade eslint-plugin-react-hooks to 7.1.x + fix flagged smells#8

Merged
iaj6 merged 1 commit into
mainfrom
chore/react-hooks-7.1
Jun 5, 2026
Merged

chore(web): upgrade eslint-plugin-react-hooks to 7.1.x + fix flagged smells#8
iaj6 merged 1 commit into
mainfrom
chore/react-hooks-7.1

Conversation

@iaj6

@iaj6 iaj6 commented Jun 5, 2026

Copy link
Copy Markdown
Owner

What

Completes the deferred follow-up from #7: it pinned eslint-plugin-react-hooks to 7.0.1 to dodge the new React Compiler lint rules. This bumps the override to 7.1.1, turns those rules on, and fixes the 12 violations they flag.

The rules now active: react-hooks/purity (no clock/impure reads in render), react-hooks/set-state-in-effect (no synchronous setState in effects), react-hooks/refs (no ref writes during render), react-hooks/immutability (no use-before-declare).

The override is kept as an explicit pin rather than removed: this plugin ships new CI-gating lint rules in minor releases, and [email protected] only requests ^7.0.0 — so a deliberate pin protects CI from a surprise float to 7.2.x.

Real fixes (behavior-preserving)

File Rule Change
hooks/useEventSource.ts refs Write onEvent into the ref from a useEffect, not during render. Only async SSE handlers read it, strictly after commit.
hooks/useSessions.ts immutability Hoist the markUpdated useCallback above its first use — declaration-order only; deps/body/call-site byte-for-byte unchanged.
settings/ApiTokensSection.tsx, settings/UsersSection.tsx set-state-in-effect Move the mount fetch into a cancellable async IIFE so setState lands after the await. Kept the try/finally so a rejected fetch / throwing res.json() can't strand the loading spinner.
events/EventLog.tsx purity Read the clock from an interval-refreshed now state instead of Date.now() during render. Strictly less churny than the prior per-render read (the since param isn't forwarded to the SSE stream, so no reconnect thrash); time-window cutoff lags ≤30s.

Scoped eslint-disables (genuine false positives)

Terminating derived-state resets (setPage(0), setSelectedIndex(0) in AuditSection / CommandPalette) and intentional point-in-time pause snapshots in EventLog. Each has a justifying comment.

Verification

  • ✅ web lint 0 errors / 0 warnings
  • npm run build green (all packages incl. Next build)
  • 1166 tests pass
  • ✅ clean npm ci (lock ↔ package.json consistent; 45 Linux optional deps preserved for Linux CI)
  • ✅ Adversarial 4-lens behavior-preservation review — caught a stranded-spinner regression on the fetch error path (missing try/finally in the inlined mount fetch), now fixed; the other 3 lenses confirmed the diff is behavior-preserving.

🤖 Generated with Claude Code

…d smells

Bumps the override from 7.0.1 (pinned in PR #7 to dodge the new rules) to
7.1.1, which activates the React Compiler lint rules (purity,
set-state-in-effect, refs, immutability), and resolves the 12 violations
they surface. Kept as an explicit pin: this plugin adds CI-gating rules in
minor releases (eslint-config-next only requests ^7.0.0), so deliberate
bumps avoid surprise breakage.

Real fixes (behavior-preserving):
- useEventSource: write onEvent into the ref from an effect, not during
  render (refs rule). Only async SSE handlers read it, after commit.
- useSessions: hoist the markUpdated useCallback above its first use
  (immutability rule) — declaration-order only.
- ApiTokens/Users settings sections: move the mount fetch into a
  cancellable async IIFE so setState lands after the await
  (set-state-in-effect), keeping the try/finally so a rejected fetch can't
  strand the loading spinner.
- EventLog: read the clock from an interval-refreshed `now` state instead
  of during render (purity). Strictly less churny than the prior
  per-render Date.now(); the time-window cutoff lags <=30s.

Scoped, justified eslint-disables for genuine false positives: terminating
derived-state resets (setPage(0), setSelectedIndex(0)) and intentional
point-in-time pause snapshots in EventLog.

Verification: web lint 0/0, full build green, 1166 tests pass, clean
npm ci. An adversarial 4-lens review caught the stranded-spinner error
path, now fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@iaj6 iaj6 merged commit 57696b0 into main Jun 5, 2026
3 checks passed
@iaj6 iaj6 deleted the chore/react-hooks-7.1 branch June 5, 2026 12:52
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