Skip to content

Commit 9595254

Browse files
alimttthautofix-ci[bot]TkDodo
authored
fix: allow useQueries with combine property in no-unstable-deps rule (#9720)
* fix: allow useQueries with combine property in no-unstable-deps rule - 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 #9718 * ci: apply automated fixes * Create ten-crabs-glow.md --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Dominik Dorfmeister <[email protected]>
1 parent b59925e commit 9595254

File tree

3 files changed

+95
-18
lines changed

3 files changed

+95
-18
lines changed

.changeset/ten-crabs-glow.md

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: allow useQueries with combine property in no-unstable-deps rule

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

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ const baseTestCases = {
2828
}
2929
`,
3030
},
31-
].concat(
32-
useQueryHookNames.map((queryHook) => ({
33-
name: `should pass result of ${queryHook} is passed to ${reactHookInvocation} as dependency`,
34-
code: `
31+
]
32+
.concat(
33+
useQueryHookNames.map((queryHook) => ({
34+
name: `should pass result of ${queryHook} is passed to ${reactHookInvocation} as dependency`,
35+
code: `
3536
${reactHookImport}
3637
import { ${queryHook} } from "@tanstack/react-query";
3738
@@ -41,8 +42,28 @@ const baseTestCases = {
4142
return;
4243
}
4344
`,
44-
})),
45-
),
45+
})),
46+
)
47+
.concat([
48+
{
49+
name: `should pass when useQueries with combine is passed to ${reactHookAlias} as dependency`,
50+
code: `
51+
${reactHookImport}
52+
import { useQueries } from "@tanstack/react-query";
53+
54+
function Component() {
55+
const queries = useQueries({
56+
queries: [
57+
{ queryKey: ['test'], queryFn: () => 'test' }
58+
],
59+
combine: (results) => ({ data: results[0]?.data })
60+
});
61+
const callback = ${reactHookInvocation}(() => { queries.data }, [queries]);
62+
return;
63+
}
64+
`,
65+
},
66+
]),
4667
invalid: ({
4768
reactHookImport,
4869
reactHookInvocation,
@@ -68,10 +89,11 @@ const baseTestCases = {
6889
},
6990
],
7091
},
71-
].concat(
72-
useQueryHookNames.map((queryHook) => ({
73-
name: `result of ${queryHook} is passed to ${reactHookInvocation} as dependency`,
74-
code: `
92+
]
93+
.concat(
94+
useQueryHookNames.map((queryHook) => ({
95+
name: `result of ${queryHook} is passed to ${reactHookInvocation} as dependency`,
96+
code: `
7597
${reactHookImport}
7698
import { ${queryHook} } from "@tanstack/react-query";
7799
@@ -81,14 +103,39 @@ const baseTestCases = {
81103
return;
82104
}
83105
`,
84-
errors: [
85-
{
86-
messageId: 'noUnstableDeps',
87-
data: { reactHook: reactHookAlias, queryHook },
88-
},
89-
],
90-
})),
91-
),
106+
errors: [
107+
{
108+
messageId: 'noUnstableDeps',
109+
data: { reactHook: reactHookAlias, queryHook },
110+
},
111+
],
112+
})),
113+
)
114+
.concat([
115+
{
116+
name: `result of useQueries without combine is passed to ${reactHookInvocation} as dependency`,
117+
code: `
118+
${reactHookImport}
119+
import { useQueries } from "@tanstack/react-query";
120+
121+
function Component() {
122+
const queries = useQueries({
123+
queries: [
124+
{ queryKey: ['test'], queryFn: () => 'test' }
125+
]
126+
});
127+
const callback = ${reactHookInvocation}(() => { queries[0]?.data }, [queries]);
128+
return;
129+
}
130+
`,
131+
errors: [
132+
{
133+
messageId: 'noUnstableDeps',
134+
data: { reactHook: reactHookAlias, queryHook: 'useQueries' },
135+
},
136+
],
137+
},
138+
]),
92139
}
93140

94141
const testCases = (reactHookName: string) => [

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ export const rule = createRule({
6767
}
6868
}
6969

70+
function hasCombineProperty(
71+
callExpression: TSESTree.CallExpression,
72+
): boolean {
73+
if (callExpression.arguments.length === 0) return false
74+
75+
const firstArg = callExpression.arguments[0]
76+
if (!firstArg || firstArg.type !== AST_NODE_TYPES.ObjectExpression)
77+
return false
78+
79+
return firstArg.properties.some(
80+
(prop) =>
81+
prop.type === AST_NODE_TYPES.Property &&
82+
prop.key.type === AST_NODE_TYPES.Identifier &&
83+
prop.key.name === 'combine',
84+
)
85+
}
86+
7087
return {
7188
ImportDeclaration(node: TSESTree.ImportDeclaration) {
7289
if (
@@ -94,6 +111,14 @@ export const rule = createRule({
94111
node.init.callee.type === AST_NODE_TYPES.Identifier &&
95112
allHookNames.includes(node.init.callee.name)
96113
) {
114+
// Special case for useQueries with combine property - it's stable
115+
if (
116+
node.init.callee.name === 'useQueries' &&
117+
hasCombineProperty(node.init)
118+
) {
119+
// Don't track useQueries with combine as unstable
120+
return
121+
}
97122
collectVariableNames(node.id, node.init.callee.name)
98123
}
99124
},

0 commit comments

Comments
 (0)