Skip to content

feat(tanstack-query): add query-destructure-result rule#688

Open
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1780639912-query-destructure-result
Open

feat(tanstack-query): add query-destructure-result rule#688
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1780639912-query-destructure-result

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Jun 5, 2026

Why

Catches const result = useQuery(...) — assigning the whole TanStack Query object to a variable bypasses tracked-property optimization, subscribing the component to every field and re-rendering on any change.

Before:

const query = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
return <div>{query.data}</div>

After:

const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
return <div>{data}</div>

What changed

  • Added query-destructure-result.
  • Detects VariableDeclarator where init is a CallExpression for useQuery/useSuspenseQuery/useInfiniteQuery/useSuspenseInfiniteQuery and id is an Identifier (not destructured).
  • Reports severity error, framework tanstack-query, tagged test-noise.
  • Allows destructured patterns (const { data } = ...) and rest-destructuring (caught separately by query-no-rest-destructuring).

Eval results

Check Result
Repos scanned 4 (TanStack/query, cal.com, create-t3-app, TanStack/router)
Target rule query-destructure-result
Diagnostics 121 (15 + 16 + 0 + 90)
False positives found 0 (manually inspected all cal.com + query hits, sampled router)

Test plan

  • cd packages/oxlint-plugin-react-doctor && nr test — passes (pre-existing failures in unrelated jsx-no-new-* rules only)
  • npx tsc --noEmit — passes
  • nr lint — pre-existing Node.js version issue (needs >=22.18.0), unrelated

Link to Devin session: https://app.devin.ai/sessions/26bb7313d5254e48aa4832c0ccc25691
Requested by: @aidenybai


Open in Devin Review

Note

Low Risk
Additive lint rule and registry entry only; no runtime or security behavior changes.

Overview
Adds query-destructure-result, a TanStack Query lint that errors when a query hook return value is bound to a single identifier (e.g. const query = useQuery(...)) instead of destructuring fields like { data, isLoading }.

The rule visits VariableDeclarator nodes, matches direct calls to useQuery / useSuspenseQuery / useInfiniteQuery / useSuspenseInfiniteQuery via TANSTACK_QUERY_HOOKS, and only fires when id is an Identifier—object destructuring is allowed; rest patterns remain covered by query-no-rest-destructuring. It is registered under framework tanstack-query, category Bugs, severity error, with a patch changeset for oxlint-plugin-react-doctor.

Reviewed by Cursor Bugbot for commit 766583f. Bugbot is set up for automated code reviews on this repo. Configure here.

Co-Authored-By: Aiden Bai <aiden.bai05@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 5, 2026

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-react-doctor@688
npm i https://pkg.pr.new/oxlint-plugin-react-doctor@688
npm i https://pkg.pr.new/react-doctor@688

commit: 766583f

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 5, 2026

No React Doctor issues found. 🎉

Reviewed by React Doctor for commit 766583f.

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

title: "Destructure TanStack Query result",
tags: ["test-noise"],
requires: ["tanstack-query"],
severity: "error",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 Severity "error" inconsistent with all other tanstack-query rules which use "warn"

The new query-destructure-result rule uses severity: "error" while every other tanstack-query rule in the codebase uses severity: "warn" — including query-no-rest-destructuring (query-no-rest-destructuring.ts:14), which addresses the exact same tracked-property optimization concern and even gives a near-identical recommendation ("Destructure only the fields you need…subscribes to every field and adds re-renders"). Since the default rule severity flows through to the oxlint config (packages/core/src/runners/oxlint/config.ts:137), this rule will fire as an error (potentially failing CI) for a performance hint that its sibling rule treats as a warning.

Suggested change
severity: "error",
severity: "warn",
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Keeping severity: "error" — this matches the spec provided by the requester (screenshot shows severity: error). Assigning the whole query object completely defeats TanStack Query's tracked-property optimization, which is a stronger signal than rest-destructuring (which at least destructures some fields).

@aidenybai
Copy link
Copy Markdown
Member

/rde parity

@react-doctor-evals
Copy link
Copy Markdown

react-doctor-evals Bot commented Jun 5, 2026

❌ Parity failed — trace 28f1a153853885c9f37bd5d77b65a207. Check server logs for that trace ID.

Co-Authored-By: Aiden Bai <aiden.bai05@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

RDE parity results:

Repo Total diagnostics query-destructure-result hits
TanStack/query 1856 15
cal.com/cal.com 3056 16
t3-oss/create-t3-app 157 0
TanStack/router 7114 90
Total 12183 121

False positives: 0 — manually inspected all 31 hits from query + cal.com, sampled router. Every hit is a genuine const x = useQuery(...) / useSuspenseQuery(...) / useInfiniteQuery(...) pattern.

Typical hit: const postsQuery = useSuspenseQuery(postsQueryOptions) then postsQuery.data on the next line — exactly the tracked-property bypass this rule catches.

Added changeset (oxlint-plugin-react-doctor patch).

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