Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/warm-candies-like.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
'@tanstack/react-query': minor
---

react-query: update usePrefetchQuery and usePrefetchInfiniteQuery to use queryClient.query and queryClient.infiniteQuery
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,7 +9,7 @@ usePrefetchInfiniteQuery(options)

**Options**

You can pass everything to `usePrefetchInfiniteQuery` that you can pass to [`queryClient.prefetchInfiniteQuery`](../../../reference/QueryClient.md#queryclientprefetchinfinitequery). Remember that some of them are required as below:
You can pass everything to `usePrefetchInfiniteQuery` that you can pass to [`queryClient.infiniteQuery`](../../../reference/QueryClient.md#queryclient-infinitequery). Remember that some of them are required as below:

- `queryKey: QueryKey`
- **Required**
Expand Down
4 changes: 2 additions & 2 deletions docs/framework/react/reference/usePrefetchQuery.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,13 +9,13 @@ usePrefetchQuery(options)

**Options**

You can pass everything to `usePrefetchQuery` that you can pass to [`queryClient.prefetchQuery`](../../../reference/QueryClient.md#queryclientprefetchquery). Remember that some of them are required as below:
You can pass everything to `usePrefetchQuery` that you can pass to [`queryClient.query`](../../../reference/QueryClient.md#queryclient-query). Remember that some of them are required as below:

- `queryKey: QueryKey`
- **Required**
- The query key to prefetch during render

- `queryFn: (context: QueryFunctionContext) => Promise<TData>`
- `queryFn: (context: QueryFunctionContext<TQueryKey>) => TQueryFnData | Promise<TQueryFnData>`
- **Required, but only if no default query function has been defined** See [Default Query Function](../guides/default-query-function.md) for more information.

**Returns**
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -60,6 +60,20 @@ describe('infiniteQueryOptions', () => {
InfiniteData<string, unknown> | undefined
>()
})
it('should work when passed to useInfiniteQuery with select', () => {
const options = infiniteQueryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve('string'),
getNextPageParam: () => 1,
initialPageParam: 1,
select: (data) => data.pages,
})

const { data } = useInfiniteQuery(options)

// known issue: type of pageParams is unknown when returned from useInfiniteQuery
expectTypeOf(data).toEqualTypeOf<Array<string> | undefined>()
})
it('should work when passed to useSuspenseInfiniteQuery', () => {
const options = infiniteQueryOptions({
queryKey: queryKey(),
Expand All@@ -72,6 +86,19 @@ describe('infiniteQueryOptions', () => {

expectTypeOf(data).toEqualTypeOf<InfiniteData<string, unknown>>()
})
it('should work when passed to useSuspenseInfiniteQuery with select', () => {
const options = infiniteQueryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve('string'),
getNextPageParam: () => 1,
initialPageParam: 1,
select: (data) => data.pages,
})

const { data } = useSuspenseInfiniteQuery(options)

expectTypeOf(data).toEqualTypeOf<Array<string>>()
})
it('should work when passed to infiniteQuery', async () => {
const options = infiniteQueryOptions({
queryKey: ['key'],
Expand DownExpand Up@@ -134,6 +161,19 @@ describe('infiniteQueryOptions', () => {

expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
})
it('should ignore select when passed to fetchInfiniteQuery', async () => {
const options = infiniteQueryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve('string'),
getNextPageParam: () => 1,
initialPageParam: 1,
select: (data) => data.pages,
})

const data = await new QueryClient().fetchInfiniteQuery(options)

expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
})
it('should tag the queryKey with the result type of the QueryFn', () => {
const { queryKey: tagged } = infiniteQueryOptions({
queryKey: queryKey(),
Expand Down
10 changes: 10 additions & 0 deletions packages/react-query/src/__tests__/queryOptions.test-d.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -112,6 +112,16 @@ describe('queryOptions', () => {
const data = await new QueryClient().query(options)
expectTypeOf(data).toEqualTypeOf<unknown>()
})
it('should ignore select when passed to fetchQuery', async () => {
const options = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
select: (data) => data.toString(),
})

const data = await new QueryClient().fetchQuery(options)
expectTypeOf(data).toEqualTypeOf<number>()
})
it('should work when passed to useQueries', () => {
const options = queryOptions({
queryKey: queryKey(),
Expand Down
12 changes: 12 additions & 0 deletions packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,18 @@ describe('pageParam', () => {
})
})

it('initialPageParam should define type of param passed to queryFunctionContext for infiniteQuery', () => {
const queryClient = new QueryClient()
queryClient.infiniteQuery({
queryKey: ['key'],
queryFn: ({ pageParam }) => {
expectTypeOf(pageParam).toEqualTypeOf<number>()
return Promise.resolve(pageParam)
},
initialPageParam: 1,
})
})

it('initialPageParam should define type of param passed to queryFunctionContext for prefetchInfiniteQuery', () => {
const queryClient = new QueryClient()
queryClient.prefetchInfiniteQuery({
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
import { assertType, describe, expectTypeOf, it } from 'vitest'
import { queryKey } from '@tanstack/query-test-utils'
import { usePrefetchInfiniteQuery } from '..'
import { skipToken, usePrefetchInfiniteQuery } from '..'

describe('usePrefetchInfiniteQuery', () => {
it('should return nothing', () => {
Expand DownExpand Up@@ -58,4 +58,25 @@ describe('usePrefetchInfiniteQuery', () => {
}),
)
})

it('should not allow skipToken in queryFn', () => {
assertType(
usePrefetchInfiniteQuery({
queryKey: queryKey(),
// @ts-expect-error
queryFn: skipToken,
initialPageParam: 1,
getNextPageParam: () => 1,
}),
)
assertType(
usePrefetchInfiniteQuery({
queryKey: queryKey(),
// @ts-expect-error
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
initialPageParam: 1,
getNextPageParam: () => 1,
}),
)
})
})
12 changes: 12 additions & 0 deletions packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,4 +57,16 @@ describe('usePrefetchQuery', () => {
}),
)
})

it('should type queryFn and select data independently', () => {
usePrefetchQuery<string, Error, number, { value: string }>({
queryKey: queryKey(),
queryFn: () => Promise.resolve('data'),
select: (data) => {
expectTypeOf(data).toEqualTypeOf<{ value: string }>()

return data.value.length
},
})
})
})
48 changes: 42 additions & 6 deletions packages/react-query/src/types.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,15 +5,16 @@ import type {
DefinedInfiniteQueryObserverResult,
DefinedQueryObserverResult,
DistributiveOmit,
FetchQueryOptions,
InfiniteData,
InfiniteQueryExecuteOptions,
InfiniteQueryObserverOptions,
InfiniteQueryObserverResult,
MutateFunction,
MutationObserverOptions,
MutationObserverResult,
OmitKeyof,
Override,
QueryExecuteOptions,
QueryKey,
QueryObserverOptions,
QueryObserverResult,
Expand DownExpand Up@@ -47,17 +48,52 @@ export interface UseBaseQueryOptions<
subscribed?: boolean
}

export interface UsePrefetchQueryOptions<
export type UsePrefetchQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> extends OmitKeyof<
FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
> = DistributiveOmit<
QueryExecuteOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
'queryFn'
> {
> & {
queryFn?: Exclude<
QueryExecuteOptions<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey
>['queryFn'],
SkipToken
>
}

export type UsePrefetchInfiniteQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> = DistributiveOmit<
InfiniteQueryExecuteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
'queryFn'
> & {
queryFn?: Exclude<
FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>['queryFn'],
InfiniteQueryExecuteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>['queryFn'],
SkipToken
>
}
Expand Down
13 changes: 8 additions & 5 deletions packages/react-query/src/usePrefetchInfiniteQuery.tsx
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
import { noop } from '@tanstack/query-core'
import { useQueryClient } from './QueryClientProvider'

import type {
DefaultError,
FetchInfiniteQueryOptions,
InfiniteData,
QueryClient,
QueryKey,
} from '@tanstack/query-core'
import type { UsePrefetchInfiniteQueryOptions } from './types'

export function usePrefetchInfiniteQuery<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: FetchInfiniteQueryOptions<
options: UsePrefetchInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
queryClient?: QueryClient,
) {
): void {
const client = useQueryClient(queryClient)

if (!client.getQueryState(options.queryKey)) {
client.prefetchInfiniteQuery(options)
void client.infiniteQuery(options).catch(noop)
}
}
15 changes: 12 additions & 3 deletions packages/react-query/src/usePrefetchQuery.tsx
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { noop } from '@tanstack/query-core'
import { useQueryClient } from './QueryClientProvider'

import type { DefaultError, QueryClient, QueryKey } from '@tanstack/query-core'
import type { UsePrefetchQueryOptions } from './types'

export function usePrefetchQuery<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: UsePrefetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
options: UsePrefetchQueryOptions<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey
>,
queryClient?: QueryClient,
) {
): void {
const client = useQueryClient(queryClient)

if (!client.getQueryState(options.queryKey)) {
client.prefetchQuery(options)
void client.query(options).catch(noop)
}
}