Skip to content

Conversation

alimttth
Copy link
Contributor

@alimttth alimttth commented Oct 1, 2025

Changes

Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes

    • Linting now treats useQueries calls that include a combine option as stable, avoiding false-positive no-unstable-deps warnings in React hooks.
  • Tests

    • Added tests validating useQueries scenarios with and without combine, confirming correct diagnostics for stable and unstable dependency patterns (including when the queries object is used as a hook dependency).

- Add hasCombineProperty function to detect combine property in useQueries calls
- Skip tracking useQueries with combine as unstable since combine makes result stable
- Add tests for useQueries with and without combine property
- Fixes TanStack#9718
Copy link

changeset-bot bot commented Oct 1, 2025

🦋 Changeset detected

Latest commit: 8517ada

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/eslint-plugin-query Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

coderabbitai bot commented Oct 1, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds handling so useQueries calls with a combine property are treated as stable (skipped) by the no-unstable-deps rule, and extends tests with valid and invalid cases for useQueries with and without combine.

Changes

Cohort / File(s) Summary
Rule logic: handle combine in useQueries
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
Adds hasCombineProperty(callExpression) and an early-return in VariableDeclarator handling when useQueries is called with a combine property so the resulting variable is not tracked as unstable.
Tests: extend valid/invalid cases
packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
Appends new valid and invalid test cases covering useQueries with a combine function (treated as stable) and useQueries without combine (still reported), updating concatenation logic to include these scenarios.
Changelog/metadata
.changeset/ten-crabs-glow.md
Adds a changeset bump documenting "allow useQueries with combine property in no-unstable-deps rule."

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer Code
  participant ESLint as no-unstable-deps Rule
  participant AST as AST Walker

  Dev->>ESLint: Run lint on file
  ESLint->>AST: Visit VariableDeclarator (init is CallExpression)
  alt callee is useQueries with combine
    note right of ESLint #a9d18e: hasCombineProperty -> treat as stable
    ESLint-->>AST: Skip tracking variable
  else callee is useQueries without combine
    note right of ESLint #f4c7c3: No combine -> treat as unstable
    ESLint->>AST: Track variable as unstable
  end

  AST->>ESLint: Visit React Hook call with deps
  alt deps reference tracked (unstable) variable
    ESLint-->>Dev: Report noUnstableDeps diagnostic
  else deps reference skipped/stable variable
    ESLint-->>Dev: No diagnostic
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • Newbie012

Poem

A whisker twitch, a combine switch, hooray!
I skip the chase where stable things lay.
No noisy lint, just calm delight—
I hop and nibble through the night.
Carrots for code that’s doing right. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the repository’s template because the “## 🎯 Changes” section is missing or empty, the placeholder under "## Changes" remains unfilled, and section headings do not match the required template structure. Please restructure the description to use the “## 🎯 Changes” header with a filled summary of changes, remove or replace template placeholders under “## Changes,” and ensure all required sections and headings match the repository’s description template.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the main change by stating that the no-unstable-deps rule is fixed to allow useQueries with the combine property, matching the PR’s purpose and following conventional commit style.
Linked Issues Check ✅ Passed The changes implement a helper to detect the combine property and skip tracking for useQueries with combine, update the ESLint rule accordingly, and include tests for both combine and non-combine scenarios, fully addressing the objectives from issue #9718.
Out of Scope Changes Check ✅ Passed All modifications are confined to the no-unstable-deps ESLint rule and its test file to support useQueries with combine, and there are no unrelated or extraneous changes outside the linked issue’s scope.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28e98fa and 8517ada.

📒 Files selected for processing (1)
  • .changeset/ten-crabs-glow.md (1 hunks)

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts (1)

70-81: Consider edge cases in combine property detection.

The function correctly identifies standard combine properties, but may not handle all edge cases:

  1. Spread properties: { ...config, queries: [...] } won't be detected if combine is in the spread
  2. Computed property names: { ['combine']: fn } won't match since you check prop.key.type === AST_NODE_TYPES.Identifier
  3. Property shorthand: While { combine } should work, the function assumes the property key name is what matters

For robustness, consider adding a check for computed properties:

 function hasCombineProperty(callExpression: TSESTree.CallExpression): boolean {
   if (callExpression.arguments.length === 0) return false
 
   const firstArg = callExpression.arguments[0]
   if (!firstArg || firstArg.type !== AST_NODE_TYPES.ObjectExpression) return false
 
   return firstArg.properties.some(prop =>
     prop.type === AST_NODE_TYPES.Property &&
+    !prop.computed &&
     prop.key.type === AST_NODE_TYPES.Identifier &&
     prop.key.name === 'combine'
   )
 }

This ensures computed properties like { ['combine']: fn } are excluded (though they're unlikely in practice).

packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts (1)

110-134: Consider adding invalid test case for useSuspenseQueries without combine.

The invalid test case correctly verifies that useQueries without combine triggers the rule. For completeness and symmetry with the valid test cases, consider adding a corresponding invalid test for useSuspenseQueries without combine.

Add this test case to the invalid array:

{
  name: `result of useSuspenseQueries without combine is passed to ${reactHookInvocation} as dependency`,
  code: `
      ${reactHookImport}
      import { useSuspenseQueries } from "@tanstack/react-query";

      function Component() {
        const queries = useSuspenseQueries({
          queries: [
            { queryKey: ['test'], queryFn: () => 'test' }
          ]
        });
        const callback = ${reactHookInvocation}(() => { queries[0]?.data }, [queries]);
        return;
      }
    `,
  errors: [
    {
      messageId: 'noUnstableDeps',
      data: { reactHook: reactHookAlias, queryHook: 'useSuspenseQueries' },
    },
  ],
},
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f82d8e and c6cfbf0.

📒 Files selected for processing (2)
  • packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts (2 hunks)
  • packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts (2 hunks)

Copy link

nx-cloud bot commented Oct 4, 2025

View your CI Pipeline Execution ↗ for commit 07a1be7

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 1m 7s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 6s View ↗

☁️ Nx Cloud last updated this comment at 2025-10-16 08:12:37 UTC

Copy link

pkg-pr-new bot commented Oct 16, 2025

More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9720

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9720

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9720

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9720

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@9720

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@9720

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9720

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9720

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@9720

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@9720

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9720

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9720

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@9720

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9720

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9720

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@9720

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9720

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9720

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@9720

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9720

commit: 07a1be7

Copy link

codecov bot commented Oct 16, 2025

Codecov Report

❌ Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.56%. Comparing base (b59925e) to head (07a1be7).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #9720       +/-   ##
===========================================
+ Coverage   45.56%   83.56%   +38.00%     
===========================================
  Files         196       19      -177     
  Lines        8327      572     -7755     
  Branches     1895      212     -1683     
===========================================
- Hits         3794      478     -3316     
+ Misses       4091       72     -4019     
+ Partials      442       22      -420     
Components Coverage Δ
@tanstack/angular-query-experimental ∅ <ø> (∅)
@tanstack/eslint-plugin-query 83.56% <92.30%> (+0.20%) ⬆️
@tanstack/query-async-storage-persister ∅ <ø> (∅)
@tanstack/query-broadcast-client-experimental ∅ <ø> (∅)
@tanstack/query-codemods ∅ <ø> (∅)
@tanstack/query-core ∅ <ø> (∅)
@tanstack/query-devtools ∅ <ø> (∅)
@tanstack/query-persist-client-core ∅ <ø> (∅)
@tanstack/query-sync-storage-persister ∅ <ø> (∅)
@tanstack/query-test-utils ∅ <ø> (∅)
@tanstack/react-query ∅ <ø> (∅)
@tanstack/react-query-devtools ∅ <ø> (∅)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client ∅ <ø> (∅)
@tanstack/solid-query ∅ <ø> (∅)
@tanstack/solid-query-devtools ∅ <ø> (∅)
@tanstack/solid-query-persist-client ∅ <ø> (∅)
@tanstack/svelte-query ∅ <ø> (∅)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client ∅ <ø> (∅)
@tanstack/vue-query ∅ <ø> (∅)
@tanstack/vue-query-devtools ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@TkDodo TkDodo merged commit 9595254 into TanStack:main Oct 16, 2025
1 of 2 checks passed
@github-actions github-actions bot mentioned this pull request Oct 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positive in @tanstack/query/no-unstable-deps ESLint rule with combine property

2 participants