Skip to content

fix(eslint-plugin-query): handle array-destructured useQueries results in no-unstable-deps (fix #10746)#10747

Open
vinamra1102 wants to merge 4 commits into
TanStack:mainfrom
vinamra1102:main
Open

fix(eslint-plugin-query): handle array-destructured useQueries results in no-unstable-deps (fix #10746)#10747
vinamra1102 wants to merge 4 commits into
TanStack:mainfrom
vinamra1102:main

Conversation

@vinamra1102
Copy link
Copy Markdown

@vinamra1102 vinamra1102 commented May 21, 2026

What does this PR fix?

The no-unstable-deps rule silently ignores array-destructured results
from useQueries and useSuspenseQueries. Writing:

const [userQuery, postsQuery] = useQueries({ queries: [...] })

causes neither variable to be tracked as unstable, so using them in
useEffect dependency arrays is never flagged — even though it should be.

Root cause

collectVariableNames in no-unstable-deps.rule.ts only handled
Identifier patterns. When the result is array-destructured, the id
node is an ArrayPattern which was silently ignored.

Evidence this is unintentional

The sibling rule no-rest-destructuring already handles ArrayPattern
correctly for useQueries and useSuspenseQueries (lines 69–86 of
no-rest-destructuring.rule.ts), confirming this pattern is expected
and no-unstable-deps had a gap.

Fix

Added ArrayPattern handling to collectVariableNames to iterate over
elements and track each destructured variable individually, including
rest elements.

Tests added

  • Invalid: useQueries array element used as dep → flagged
  • Invalid: useSuspenseQueries array element used as dep → flagged
  • Invalid: rest element (...restQueries) used as dep → flagged

Related issue

Fixes #10746

Summary by CodeRabbit

  • Bug Fixes

    • ESLint rule "no-unstable-deps" now correctly detects unstable dependencies when query-hook results are array-destructured (covers both standard and suspense query hooks).
  • Tests

    • Added test cases validating array-destructured return values and rest-element usage trigger expected rule reports.
  • Chores

    • Added a changeset to publish a patch release.

Review Change Stack

vinamra1102 and others added 2 commits May 21, 2026 11:39
…s in no-unstable-deps

The `collectVariableNames` function in the `no-unstable-deps` rule only
handled `Identifier` patterns. When users array-destructure `useQueries`
or `useSuspenseQueries` results (e.g. `const [q1, q2] = useQueries(...)`),
the individual variables were not tracked as unstable. This meant passing
them directly to React hook dependency arrays was never flagged.

Extend `collectVariableNames` to also handle `ArrayPattern` — including
plain identifier elements and rest elements.

Fixes TanStack#10746
…tern

fix(eslint-plugin-query): handle array-destructured useQueries result…
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

Fixes a false negative in the no-unstable-deps ESLint rule by recognizing array-destructured results from useQueries/useSuspenseQueries; adds tests and a changeset documenting a patch release.

Changes

Array Destructuring Support for no-unstable-deps

Layer / File(s) Summary
Array pattern handling in collectVariableNames
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
collectVariableNames now recognizes ArrayPattern bindings, iterating through destructured elements and mapping identifiers (including rest elements) to their originating query hook name.
Test coverage for array destructuring patterns
packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
Valid test case confirms array-destructured element properties are stable; invalid test cases confirm the rule flags whole elements and rest arrays from useQueries and useSuspenseQueries as unstable dependencies.
Patch release documentation
.changeset/fix-no-unstable-deps-array-pattern.md
Changeset marks a patch release documenting the fix for handling array-destructured useQueries and useSuspenseQueries results.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

package: eslint-plugin-query

Poem

🐰 I nibble through brackets, sniffing each name,
Destructured queries now tracked just the same,
Tests hop alongside, a tidy patch trail,
ESLint sings softly — no unstable fail!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: fixing the no-unstable-deps rule to handle array-destructured useQueries results, and references the related issue #10746.
Description check ✅ Passed The PR description is detailed and comprehensive, explaining the bug, root cause, evidence, fix, and tests added. However, it does not follow the template structure with 'Changes' section or the checklist items.
Linked Issues check ✅ Passed The PR directly addresses all coding requirements from issue #10746: handling ArrayPattern in collectVariableNames, tracking destructured variables as unstable, and adding test cases for useQueries and useSuspenseQueries array elements and rest elements as dependencies.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #10746: a changeset entry, test cases for the bug scenario, and the rule implementation fix for array-destructured patterns. No extraneous changes are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts`:
- Around line 67-80: In collectVariableNames, ArrayPattern handling currently
only records Identifier and RestElement identifiers and misses AssignmentPattern
elements (e.g., const [q = fallback] = useQueries(...)); add a branch to treat
element.type === AST_NODE_TYPES.AssignmentPattern and, when element.left.type
=== AST_NODE_TYPES.Identifier, register trackedVariables[element.left.name] =
queryHook (similarly handle RestElement whose argument might be an
AssignmentPattern if applicable) so default-value array destructuring is
tracked.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a3f0b505-6822-4e93-aa85-85c7e1e82dfc

📥 Commits

Reviewing files that changed from the base of the PR and between 3a5753f and 6ce381a.

📒 Files selected for processing (3)
  • .changeset/fix-no-unstable-deps-array-pattern.md
  • packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
  • packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts

@vinamra1102
Copy link
Copy Markdown
Author

Updated the PR to also handle AssignmentPattern elements in array
destructuring (e.g. const [query = fallback] = useQueries(...)),
as suggested by CodeRabbit.

Workflows are awaiting approval could a maintainer please approve
CI to run? Happy to address any further feedback. Thank you!

Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts (1)

205-276: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add one regression test for default-value array destructuring (AssignmentPattern).

Please add an invalid case like const [query = fallback] = useQueries(...) (and/or useSuspenseQueries) used in deps, so this path is locked by tests alongside element/rest coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts` around
lines 205 - 276, Add a failing test that covers array-destructuring with a
default value (AssignmentPattern) being used in hook deps: add cases similar to
the existing ones that declare "const [query = fallback] = useQueries(...)" and
"const [query = fallback] = useSuspenseQueries(...)" and then pass `query` in
the dependency array for the dynamic react hook invocation (use the existing
test variables reactHookImport, reactHookInvocation/reactHookAlias and queryHook
names). Ensure each test includes an errors entry with messageId
'noUnstableDeps' and data { reactHook: reactHookAlias, queryHook: 'useQueries' }
or 'useSuspenseQueries' as appropriate so the AssignmentPattern path is
exercised.
♻️ Duplicate comments (1)
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts (1)

67-80: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing AssignmentPattern support in array destructuring still leaves a false-negative path.

collectVariableNames still skips cases like const [query = fallback] = useQueries(...), so those bindings won’t be tracked and won’t be reported in dependency arrays. Please recurse on AssignmentPattern.left in the ArrayPattern loop.

#!/bin/bash
# Verify whether AssignmentPattern is handled in collectVariableNames and whether related tests exist.
rg -n "function collectVariableNames|ArrayPattern|AssignmentPattern|RestElement" \
  packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts -C4

rg -n "useQueries|useSuspenseQueries|\\[.*=.*\\]|AssignmentPattern" \
  packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts -C3
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts`
around lines 67 - 80, collectVariableNames currently ignores AssignmentPattern
nodes inside an ArrayPattern (e.g., const [query = fallback] = useQueries(...)),
causing false-negatives; update the ArrayPattern handling in
collectVariableNames to detect when an element.type ===
AST_NODE_TYPES.AssignmentPattern and then recurse or process its left child
(element.left) the same way you handle an Identifier (and RestElement.argument),
adding trackedVariables[element.left.name] = queryHook (or delegating to
collectVariableNames on element.left) so defaulted bindings are tracked.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts`:
- Around line 205-276: Add a failing test that covers array-destructuring with a
default value (AssignmentPattern) being used in hook deps: add cases similar to
the existing ones that declare "const [query = fallback] = useQueries(...)" and
"const [query = fallback] = useSuspenseQueries(...)" and then pass `query` in
the dependency array for the dynamic react hook invocation (use the existing
test variables reactHookImport, reactHookInvocation/reactHookAlias and queryHook
names). Ensure each test includes an errors entry with messageId
'noUnstableDeps' and data { reactHook: reactHookAlias, queryHook: 'useQueries' }
or 'useSuspenseQueries' as appropriate so the AssignmentPattern path is
exercised.

---

Duplicate comments:
In
`@packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts`:
- Around line 67-80: collectVariableNames currently ignores AssignmentPattern
nodes inside an ArrayPattern (e.g., const [query = fallback] = useQueries(...)),
causing false-negatives; update the ArrayPattern handling in
collectVariableNames to detect when an element.type ===
AST_NODE_TYPES.AssignmentPattern and then recurse or process its left child
(element.left) the same way you handle an Identifier (and RestElement.argument),
adding trackedVariables[element.left.name] = queryHook (or delegating to
collectVariableNames on element.left) so defaulted bindings are tracked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd8c54c6-1809-4bba-b223-cd2ba9b71c45

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce381a and 41ad999.

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

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.

[Bug] no-unstable-deps rule misses array-destructured useQueries results

2 participants