146 lines
3.2 KiB
Markdown
146 lines
3.2 KiB
Markdown
---
|
|
id: prefer-query-options
|
|
title: Prefer the use of queryOptions
|
|
---
|
|
|
|
Separating `queryKey` and `queryFn` can cause unexpected runtime issues when the same query key is accidentally used with more than one `queryFn`. Wrapping them in `queryOptions` (or `infiniteQueryOptions`) co-locates the key and function, making queries safer and easier to reuse.
|
|
|
|
## Rule Details
|
|
|
|
Examples of **incorrect** code for this rule:
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function Component({ id }) {
|
|
const query = useQuery({
|
|
queryKey: ['get', id],
|
|
queryFn: () => Api.get(`/foo/${id}`),
|
|
})
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function useFooQuery(id) {
|
|
return useQuery({
|
|
queryKey: ['get', id],
|
|
queryFn: () => Api.get(`/foo/${id}`),
|
|
})
|
|
}
|
|
```
|
|
|
|
Examples of **correct** code for this rule:
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function getFooOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['get', id],
|
|
queryFn: () => Api.get(`/foo/${id}`),
|
|
})
|
|
}
|
|
|
|
function Component({ id }) {
|
|
const query = useQuery(getFooOptions(id))
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function getFooOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['get', id],
|
|
queryFn: () => Api.get(`/foo/${id}`),
|
|
})
|
|
}
|
|
|
|
function useFooQuery(id) {
|
|
return useQuery({ ...getFooOptions(id), select: (data) => data.foo })
|
|
}
|
|
```
|
|
|
|
The rule also enforces reusing `queryKey` from a `queryOptions` result instead of typing it manually in `QueryClient` methods or filters.
|
|
|
|
Examples of **incorrect** `queryKey` references for this rule:
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function todoOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['todo', id],
|
|
queryFn: () => api.getTodo(id),
|
|
})
|
|
}
|
|
|
|
function Component({ id }) {
|
|
const queryClient = useQueryClient()
|
|
return queryClient.getQueryData(['todo', id])
|
|
}
|
|
```
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function todoOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['todo', id],
|
|
queryFn: () => api.getTodo(id),
|
|
})
|
|
}
|
|
|
|
function Component({ id }) {
|
|
const queryClient = useQueryClient()
|
|
return queryClient.invalidateQueries({ queryKey: ['todo', id] })
|
|
}
|
|
```
|
|
|
|
Examples of **correct** `queryKey` references for this rule:
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function todoOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['todo', id],
|
|
queryFn: () => api.getTodo(id),
|
|
})
|
|
}
|
|
|
|
function Component({ id }) {
|
|
const queryClient = useQueryClient()
|
|
return queryClient.getQueryData(todoOptions(id).queryKey)
|
|
}
|
|
```
|
|
|
|
```tsx
|
|
/* eslint "@tanstack/query/prefer-query-options": "error" */
|
|
|
|
function todoOptions(id) {
|
|
return queryOptions({
|
|
queryKey: ['todo', id],
|
|
queryFn: () => api.getTodo(id),
|
|
})
|
|
}
|
|
|
|
function Component({ id }) {
|
|
const queryClient = useQueryClient()
|
|
return queryClient.invalidateQueries({ queryKey: todoOptions(id).queryKey })
|
|
}
|
|
```
|
|
|
|
## When Not To Use It
|
|
|
|
If you do not want to enforce the use of `queryOptions` in your codebase, you will not need this rule.
|
|
|
|
## Attributes
|
|
|
|
- [x] ✅ Recommended (strict)
|
|
- [ ] 🔧 Fixable
|