Skip to content

Commit 2ccdae8

Browse files
vinamra1102TkDodoautofix-ci[bot]
authored
fix(eslint-plugin-query): handle array-destructured useQueries results in no-unstable-deps (fix #10746) (#10747)
* fix(eslint-plugin-query): handle array-destructured useQueries results 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 #10746 * ci: apply automated fixes --------- Co-authored-by: Dominik Dorfmeister 🔮 <office@dorfmeister.cc> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent b9eb3af commit 2ccdae8

3 files changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack/eslint-plugin-query": patch
3+
---
4+
5+
fix(no-unstable-deps): handle array-destructured useQueries and useSuspenseQueries results

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

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ const baseTestCases = {
8282
`,
8383
},
8484
])
85+
.concat([
86+
{
87+
name: `should pass when useQueries is array-destructured and element properties are used with ${reactHookAlias}`,
88+
code: `
89+
${reactHookImport}
90+
import { useQueries } from "@tanstack/react-query";
91+
92+
function Component() {
93+
const [{ data }] = useQueries({
94+
queries: [
95+
{ queryKey: ['test'], queryFn: () => 'test' }
96+
]
97+
});
98+
const callback = ${reactHookInvocation}(() => { data }, [data]);
99+
return;
100+
}
101+
`,
102+
},
103+
])
85104
.concat([
86105
{
87106
name: `should pass when useQuery is imported from non-TanStack source and used with ${reactHookAlias}`,
@@ -181,6 +200,82 @@ const baseTestCases = {
181200
},
182201
],
183202
},
203+
])
204+
.concat([
205+
{
206+
name: `array-destructured useQueries element is passed to ${reactHookInvocation} as dependency`,
207+
code: `
208+
${reactHookImport}
209+
import { useQueries } from "@tanstack/react-query";
210+
211+
function Component() {
212+
const [userQuery, postsQuery] = useQueries({
213+
queries: [
214+
{ queryKey: ['user'], queryFn: () => 'user' },
215+
{ queryKey: ['posts'], queryFn: () => 'posts' }
216+
]
217+
});
218+
const callback = ${reactHookInvocation}(() => { userQuery.data }, [userQuery]);
219+
return;
220+
}
221+
`,
222+
errors: [
223+
{
224+
messageId: 'noUnstableDeps',
225+
data: { reactHook: reactHookAlias, queryHook: 'useQueries' },
226+
},
227+
],
228+
},
229+
{
230+
name: `array-destructured useSuspenseQueries element is passed to ${reactHookInvocation} as dependency`,
231+
code: `
232+
${reactHookImport}
233+
import { useSuspenseQueries } from "@tanstack/react-query";
234+
235+
function Component() {
236+
const [query] = useSuspenseQueries({
237+
queries: [
238+
{ queryKey: ['test'], queryFn: () => 'test' }
239+
]
240+
});
241+
const callback = ${reactHookInvocation}(() => { query.data }, [query]);
242+
return;
243+
}
244+
`,
245+
errors: [
246+
{
247+
messageId: 'noUnstableDeps',
248+
data: {
249+
reactHook: reactHookAlias,
250+
queryHook: 'useSuspenseQueries',
251+
},
252+
},
253+
],
254+
},
255+
{
256+
name: `rest element of array-destructured useQueries is passed to ${reactHookInvocation} as dependency`,
257+
code: `
258+
${reactHookImport}
259+
import { useQueries } from "@tanstack/react-query";
260+
261+
function Component() {
262+
const [firstQuery, ...restQueries] = useQueries({
263+
queries: [
264+
{ queryKey: ['a'], queryFn: () => 'a' },
265+
{ queryKey: ['b'], queryFn: () => 'b' }
266+
]
267+
});
268+
const callback = ${reactHookInvocation}(() => {}, [restQueries]);
269+
return;
270+
}
271+
`,
272+
errors: [
273+
{
274+
messageId: 'noUnstableDeps',
275+
data: { reactHook: reactHookAlias, queryHook: 'useQueries' },
276+
},
277+
],
278+
},
184279
]),
185280
}
186281

packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ export const rule = createRule({
6464
) {
6565
if (pattern.type === AST_NODE_TYPES.Identifier) {
6666
trackedVariables[pattern.name] = queryHook
67+
} else if (pattern.type === AST_NODE_TYPES.ArrayPattern) {
68+
for (const element of pattern.elements) {
69+
if (element === null) {
70+
continue
71+
}
72+
if (element.type === AST_NODE_TYPES.Identifier) {
73+
trackedVariables[element.name] = queryHook
74+
} else if (
75+
element.type === AST_NODE_TYPES.RestElement &&
76+
element.argument.type === AST_NODE_TYPES.Identifier
77+
) {
78+
trackedVariables[element.argument.name] = queryHook
79+
}
80+
}
6781
}
6882
}
6983

0 commit comments

Comments
 (0)