Skip to content

ref(lint): enable oxlint react/hooks - #124845

Open
ryan953 wants to merge 4 commits into
masterfrom
ryan953/oxlint-react-hooks
Open

ryan953 wants to merge 4 commits into
masterfrom
ryan953/oxlint-react-hooks

Conversation

@ryan953

@ryan953 ryan953 commented Sep 17, 2026

Copy link
Copy Markdown
Member

Turns on oxlint's react/hooks rule, which was parked at 'off' behind a
TODO in oxlint.config.ts. The rule is part of the React Compiler set and
catches three things: a hook referenced as a value instead of being called, a
hook whose identity can change between renders, and a hook called
conditionally.

The tree had 48 violations across 28 files. One is a real bug, the rest are
deliberate indirection.

The bug. In the issue stream, the Affected Users tooltip tested the
imported usePageFilters hook rather than the useFilteredStats prop that its
sibling groupCount block uses. A function reference is always truthy, so
disabled was permanently false and the tooltip showed even when the stream
was not displaying filtered stats.

-      disabled={!usePageFilters}
+      disabled={!useFilteredStats}

Everything else is a place where a hook is reached through a value, so
React Compiler cannot prove the binding is stable. Three patterns cover all of
them, and each suppression carries the reason it is safe:

  • The override registry (getOverride('react-hook:…')), which lets getsentry
    swap a hook implementation into the open-source frontend. Overrides register
    once before React renders, so the binding is fixed for the life of the app.
  • useProgressiveQuery, which receives the query hook as an argument so it can
    run it at more than one accuracy tier.
  • A dataset config or a call-site flag choosing between query hooks, where the
    selector is constant for the lifetime of the component.

None of these can be fixed without redesigning the mechanism itself, which is
well outside a lint sweep. The alternative — leaving the rule off — keeps the
real bug above invisible and lets the pattern spread, so suppressing with a
written reason seemed the better trade.

Reviewers may notice two directive spellings. Most sites use the repo's usual
// oxlint-disable-next-line, but where the diagnostic anchors to a line in
the middle of a wrapped expression, a preceding line cannot cover it, so those
use the trailing // oxlint-disable-line form instead. Inserting extra lines
there would also risk detaching a neighbouring directive from its target.

Also renames a useParamsValue test local to paramsValue; the use prefix
made the rule read it as a hook.

No feature flag — the behavior change is the one tooltip fix, gated on nothing.

The groupUsersCount tooltip tested the imported usePageFilters hook rather
than the useFilteredStats prop its sibling groupCount block uses. A function
reference is always truthy, so disabled was permanently false and the tooltip
appeared even when the stream was not showing filtered stats.

Also renames a useParamsValue test local to paramsValue; the use prefix made
it read as a hook. Both were found by turning on oxlint's react/hooks rule.
…tion

Every remaining react/hooks violation is a place where a hook is reached
through a value rather than a static import, so React Compiler cannot prove
the identity is stable. Three patterns cover all of them:

- The override registry, which swaps a hook implementation for getsentry SaaS.
  Overrides register once before React renders, so the binding is fixed.
- useProgressiveQuery, which takes the query hook as an argument so it can run
  it at more than one accuracy tier.
- A dataset config or call-site flag selecting between query hooks, where the
  selector is constant for the lifetime of the component.

None of these are fixable without redesigning the mechanism, so each site gets
an oxlint-disable with the reason it is safe. Sites whose anchor is inside a
wrapped expression use the trailing -disable-line form, because a preceding
line cannot cover them and inserting one risks detaching a neighbouring
directive.
Now that the tree is clean, turning the rule on keeps the remaining hook
indirection from spreading. Each existing exception carries a written reason,
so a new violation has to argue for itself rather than land silently.
@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Sep 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable rename to make the compiler happy

Comment thread static/app/components/stream/group.tsx Outdated
@ryan953
ryan953 marked this pull request as ready for review September 17, 2026 22:03
@ryan953
ryan953 requested review from a team as code owners September 17, 2026 22:03

const groupUsersCount = (
<Tooltip
disabled={!usePageFilters}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this was looking at the function called usePageFilters. Which is always defined, so this is never disabled.

Co-authored-by: Ryan Albrecht <ryan@ryanalbrecht.ca>
@@ -643,7 +643,6 @@ export function StreamGroup({

const groupUsersCount = (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The Tooltip for groupUsersCount is missing the disabled={!useFilteredStats} prop, so it is always enabled. The original bug this PR intended to fix remains.
Severity: LOW

Suggested Fix

Add the disabled={!useFilteredStats} prop to the Tooltip component wrapping groupUsersCount, similar to how it is used for the groupCount tooltip. This will ensure the tooltip is only enabled when filtered stats are being shown.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/components/stream/group.tsx#L644

Potential issue: The pull request attempted to fix an issue where the "Affected Users"
tooltip was always enabled. The change removed the incorrect
`disabled={!usePageFilters}` prop from the `Tooltip` component for `groupUsersCount` but
failed to add the intended replacement, `disabled={!useFilteredStats}`. Because the
`Tooltip` component defaults to being enabled when the `disabled` prop is not provided,
the tooltip remains always visible on hover, even when filtered stats are not being
displayed. This means the original bug was not fixed.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not the original bug this PR is aiming at

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

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants