eslint.config.js).eslintrc)TanStack Query 自带 ESLint 插件。此插件用于强制执行最佳实践,并帮助您避免常见错误。
该插件是一个独立的包,您需要安装它:
npm i -D @tanstack/eslint-plugin-query
npm i -D @tanstack/eslint-plugin-query
或者
pnpm add -D @tanstack/eslint-plugin-query
pnpm add -D @tanstack/eslint-plugin-query
或者
yarn add -D @tanstack/eslint-plugin-query
yarn add -D @tanstack/eslint-plugin-query
或者
bun add -D @tanstack/eslint-plugin-query
bun add -D @tanstack/eslint-plugin-query
要为我们的插件启用所有推荐的规则,请添加以下配置:
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
...pluginQuery.configs['flat/recommended'],
// 任何其他配置...
]
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
...pluginQuery.configs['flat/recommended'],
// 任何其他配置...
]
或者,您可以加载插件并仅配置您想要使用的规则:
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
{
plugins: {
'@tanstack/query': pluginQuery,
},
rules: {
'@tanstack/query/exhaustive-deps': 'error',
},
},
// 任何其他配置...
]
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
{
plugins: {
'@tanstack/query': pluginQuery,
},
rules: {
'@tanstack/query/exhaustive-deps': 'error',
},
},
// 任何其他配置...
]
要为我们的插件启用所有推荐的规则,请在 extends 中添加 plugin:@tanstack/query/recommended:
{
"extends": ["plugin:@tanstack/query/recommended"]
}
{
"extends": ["plugin:@tanstack/query/recommended"]
}
或者,将 @tanstack/query 添加到 plugins 部分,并配置您想要使用的规则:
{
"plugins": ["@tanstack/query"],
"rules": {
"@tanstack/query/exhaustive-deps": "error"
}
}
{
"plugins": ["@tanstack/query"],
"rules": {
"@tanstack/query/exhaustive-deps": "error"
}
}
查询键应被视为查询函数的依赖数组:查询函数内部使用的每个变量都应添加到查询键中。 这确保了查询被独立缓存,并且当变量更改时查询会自动重新获取。
此规则的不正确代码示例:
/* eslint "@tanstack/query/exhaustive-deps": "error" */
useQuery({
queryKey: ['todo'],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo'], queryFn: () => api.getTodo(id) }),
}
/* eslint "@tanstack/query/exhaustive-deps": "error" */
useQuery({
queryKey: ['todo'],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo'], queryFn: () => api.getTodo(id) }),
}
此规则的正确代码示例:
useQuery({
queryKey: ['todo', todoId],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo', id], queryFn: () => api.getTodo(id) }),
}
useQuery({
queryKey: ['todo', todoId],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo', id], queryFn: () => api.getTodo(id) }),
}
如果您不关心查询键的规则,则不需要此规则。
对于以下函数,由于类型推断,传递的对象中的属性顺序很重要:
正确的属性顺序如下:
所有其他属性对顺序不敏感,因为它们不依赖于类型推断。
此规则的不正确代码示例:
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
maxPages: 3,
})
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
maxPages: 3,
})
此规则的正确代码示例:
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
maxPages: 3,
})
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
maxPages: 3,
})
在查询结果上使用对象剩余解构会自动订阅查询结果的每个字段,这可能会导致不必要的重新渲染。 这确保您只订阅实际需要的字段。
此规则的不正确代码示例:
/* eslint "@tanstack/query/no-rest-destructuring": "warn" */
const useTodos = () => {
const { data: todos, ...rest } = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
return { todos, ...rest }
}
/* eslint "@tanstack/query/no-rest-destructuring": "warn" */
const useTodos = () => {
const { data: todos, ...rest } = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
return { todos, ...rest }
}
此规则的正确代码示例:
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
// 普通的对象解构是可以的
const { data: todos } = todosQuery
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
// 普通的对象解构是可以的
const { data: todos } = todosQuery
如果您手动设置 notifyOnChangeProps 选项,则可以禁用此规则。 由于您未使用跟踪查询,因此您有责任指定哪些道具应触发重新渲染。
从以下查询钩子返回的对象在引用上不稳定:
从这些钩子返回的对象不应直接放入 React 钩子(例如 useEffect、useMemo、useCallback)的依赖数组中。 相反,应解构查询钩子的返回值,并将解构后的值传递到 React 钩子的依赖数组中。
此规则的不正确代码示例:
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const mutation = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutation.mutate('hello')
}, [mutation])
return null
}
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const mutation = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutation.mutate('hello')
}, [mutation])
return null
}
此规则的正确代码示例:
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const { mutate } = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutate('hello')
}, [mutate])
return null
}
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const { mutate } = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutate('hello')
}, [mutate])
return null
}
查询函数必须返回一个将被 TanStack Query 缓存的值。不返回值的函数(void 函数)可能导致意外行为,并可能表明实现中存在错误。
此规则的不正确代码示例:
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
await api.todos.fetch() // 函数未返回获取的数据
},
})
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
await api.todos.fetch() // 函数未返回获取的数据
},
})
此规则的正确代码示例:
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
const todos = await api.todos.fetch()
return todos
},
})
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
const todos = await api.todos.fetch()
return todos
},
})
QueryClient 包含 QueryCache,因此您只想为应用程序的生命周期创建一个 QueryClient 实例 - _而不是_在每次渲染时创建一个新实例。
例外:允许在异步服务器组件内部创建一个新的 QueryClient,因为异步函数仅在服务器上调用一次。
此规则的不正确代码示例:
/* eslint "@tanstack/query/stable-query-client": "error" */
function App() {
const queryClient = new QueryClient()
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
/* eslint "@tanstack/query/stable-query-client": "error" */
function App() {
const queryClient = new QueryClient()
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
此规则的正确代码示例:
function App() {
const [queryClient] = useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
function App() {
const [queryClient] = useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
)
}
async function App() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(options)
}
async function App() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(options)
}