Is this approch for passing queryOptions props ok? #10097
-
|
Is this approch ok or is a better approch for passing props to queryOptions Right now i m doing like this: # queries.ts
export const exampleQueryOptions = (
query?: APIQueryParams,
options?: Partial<UseQueryOptions<PaginatedResponse<ExampleProps>>>
) => {
...options,
queryKey: ['example', query],
queryFn: () => getExample(query),
}
# components.tsx
const { data, isPending, isFetching, isRefetching } = useQuery(
exampleQueryOptions({
page: pagination.pageIndex,
limit: pagination.pageSize,
q: globalFilter,
}, { placeholderData: keepPreviousData, }
)
)
# component2.tsx
const { data, isPending, isFetching, isRefetching } = useQuery(
exampleQueryOptions({
q: globalFilter,
}, { enabled: open, }
)
) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
Hey @bylly1 ! Two things jumped out at me. You're not using the queryOptions helper. Your factory returns a plain object. That works at runtime, but you lose onz of the reasons this pattern exists, the type-safe inference. The queryOptions() helper looks like an identity function (it just returns what you give it), but it gives TypeScript the ability to infer the return type of queryFn, catch typos on option names, and flow types correctly into queryClient.getQueryData, prefetchQuery, etc... The spread order can also be a little risky for me. In your factory you have ...options, then queryKey, then queryFn. This is actually fine as written because queryKey and queryFn come after and will always win. But the fact that you accept an options bag that can contain queryKey and queryFn is misleading for me. Someone calling it might think they can override those, but they can't. It's a confusing contract. More importantly, if someone accidentally flips the spread order during a refactor, the core query definition will breaks silently. Maybe it will be better to define your factory with queryOptions(), and override at the call by spreading : // queries.ts
import { queryOptions } from '@tanstack/react-query'
export const exampleQueryOptions = (query?: APIQueryParams) =>
queryOptions({
queryKey: ['example', query],
queryFn: () => getExample(query),
})
// component.tsx
const { data, isPending, isFetching, isRefetching } = useQuery({
...exampleQueryOptions({
page: pagination.pageIndex,
limit: pagination.pageSize,
q: globalFilter,
}),
placeholderData: keepPreviousData,
})
// component2.tsx
const { data, isPending, isFetching, isRefetching } = useQuery({
...exampleQueryOptions({
q: globalFilter,
}),
enabled: open,
})Your factory only defines what it should, the queryKey + queryFn (and maybe shared defaults like staleTime). Consumers add their per-component options (enabled, placeholderData, select, etc...) at the call where they belong. |
Beta Was this translation helpful? Give feedback.
Hey @bylly1 !
Two things jumped out at me. You're not using the queryOptions helper. Your factory returns a plain object. That works at runtime, but you lose onz of the reasons this pattern exists, the type-safe inference. The queryOptions() helper looks like an identity function (it just returns what you give it), but it gives TypeScript the ability to infer the return type of queryFn, catch typos on option names, and flow types correctly into queryClient.getQueryData, prefetchQuery, etc...
The spread order can also be a little risky for me. In your factory you have ...options, then queryKey, then queryFn. This is actually fine as written because queryKey and queryFn come after and will …