Skip to content

Commit 4c2a8e5

Browse files
committed
feat(react-query): update usePrefetchQuery to use new imperitive methods plus tests
1 parent c6fc17c commit 4c2a8e5

9 files changed

Lines changed: 140 additions & 51 deletions

.changeset/warm-candies-like.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/react-query': minor
3+
---
4+
5+
move usePrefetchQuery to use new methods

packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ describe('infiniteQueryOptions', () => {
5151
InfiniteData<string, unknown> | undefined
5252
>()
5353
})
54+
it('should work when passed to useInfiniteQuery with select', () => {
55+
const options = infiniteQueryOptions({
56+
queryKey: ['key'],
57+
queryFn: () => Promise.resolve('string'),
58+
getNextPageParam: () => 1,
59+
initialPageParam: 1,
60+
select: (data) => data.pages,
61+
})
62+
63+
const { data } = useInfiniteQuery(options)
64+
65+
// known issue: type of pageParams is unknown when returned from useInfiniteQuery
66+
expectTypeOf(data).toEqualTypeOf<Array<string> | undefined>()
67+
})
5468
it('should work when passed to useSuspenseInfiniteQuery', () => {
5569
const options = infiniteQueryOptions({
5670
queryKey: queryKey(),
@@ -63,6 +77,19 @@ describe('infiniteQueryOptions', () => {
6377

6478
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, unknown>>()
6579
})
80+
it('should work when passed to useSuspenseInfiniteQuery with select', () => {
81+
const options = infiniteQueryOptions({
82+
queryKey: ['key'],
83+
queryFn: () => Promise.resolve('string'),
84+
getNextPageParam: () => 1,
85+
initialPageParam: 1,
86+
select: (data) => data.pages,
87+
})
88+
89+
const { data } = useSuspenseInfiniteQuery(options)
90+
91+
expectTypeOf(data).toEqualTypeOf<Array<string>>()
92+
})
6693
it('should work when passed to infiniteQuery', async () => {
6794
const options = infiniteQueryOptions({
6895
queryKey: ['key'],
@@ -125,6 +152,19 @@ describe('infiniteQueryOptions', () => {
125152

126153
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
127154
})
155+
it('should ignore select when passed to fetchInfiniteQuery', async () => {
156+
const options = infiniteQueryOptions({
157+
queryKey: ['key'],
158+
queryFn: () => Promise.resolve('string'),
159+
getNextPageParam: () => 1,
160+
initialPageParam: 1,
161+
select: (data) => data.pages,
162+
})
163+
164+
const data = await new QueryClient().fetchInfiniteQuery(options)
165+
166+
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
167+
})
128168
it('should tag the queryKey with the result type of the QueryFn', () => {
129169
const { queryKey: tagged } = infiniteQueryOptions({
130170
queryKey: queryKey(),

packages/react-query/src/__tests__/queryOptions.test-d.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ describe('queryOptions', () => {
105105
const data = await new QueryClient().query(options)
106106
expectTypeOf(data).toEqualTypeOf<unknown>()
107107
})
108+
it('should ignore select when passed to fetchQuery', async () => {
109+
const options = queryOptions({
110+
queryKey: ['key'],
111+
queryFn: () => Promise.resolve(5),
112+
select: (data) => data.toString(),
113+
})
114+
115+
const data = await new QueryClient().fetchQuery(options)
116+
expectTypeOf(data).toEqualTypeOf<number>()
117+
})
108118
it('should work when passed to useQueries', () => {
109119
const options = queryOptions({
110120
queryKey: queryKey(),

packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ describe('pageParam', () => {
3838
})
3939
})
4040

41+
it('initialPageParam should define type of param passed to queryFunctionContext for infiniteQuery', () => {
42+
const queryClient = new QueryClient()
43+
queryClient.infiniteQuery({
44+
queryKey: ['key'],
45+
queryFn: ({ pageParam }) => {
46+
expectTypeOf(pageParam).toEqualTypeOf<number>()
47+
return Promise.resolve(pageParam)
48+
},
49+
initialPageParam: 1,
50+
})
51+
})
52+
4153
it('initialPageParam should define type of param passed to queryFunctionContext for prefetchInfiniteQuery', () => {
4254
const queryClient = new QueryClient()
4355
queryClient.prefetchInfiniteQuery({
Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assertType, describe, expectTypeOf, it } from 'vitest'
22
import { queryKey } from '@tanstack/query-test-utils'
3-
import { skipToken, usePrefetchQuery } from '..'
3+
import { usePrefetchQuery } from '..'
44

55
describe('usePrefetchQuery', () => {
66
it('should return nothing', () => {
@@ -12,7 +12,7 @@ describe('usePrefetchQuery', () => {
1212
expectTypeOf(result).toEqualTypeOf<void>()
1313
})
1414

15-
it('should not allow refetchInterval, enabled or throwOnError options', () => {
15+
it('should not allow refetchInterval, or throwOnError options', () => {
1616
assertType(
1717
usePrefetchQuery({
1818
queryKey: queryKey(),
@@ -22,15 +22,6 @@ describe('usePrefetchQuery', () => {
2222
}),
2323
)
2424

25-
assertType(
26-
usePrefetchQuery({
27-
queryKey: queryKey(),
28-
queryFn: () => Promise.resolve(5),
29-
// @ts-expect-error TS2345
30-
enabled: true,
31-
}),
32-
)
33-
3425
assertType(
3526
usePrefetchQuery({
3627
queryKey: queryKey(),
@@ -40,21 +31,4 @@ describe('usePrefetchQuery', () => {
4031
}),
4132
)
4233
})
43-
44-
it('should not allow skipToken in queryFn', () => {
45-
assertType(
46-
usePrefetchQuery({
47-
queryKey: queryKey(),
48-
// @ts-expect-error
49-
queryFn: skipToken,
50-
}),
51-
)
52-
assertType(
53-
usePrefetchQuery({
54-
queryKey: queryKey(),
55-
// @ts-expect-error
56-
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
57-
}),
58-
)
59-
})
6034
})

packages/react-query/src/__tests__/useQuery.promise.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,62 @@ describe('useQuery().promise', { timeout: 10_000 }, () => {
730730
expect(queryFn).toHaveBeenCalledOnce()
731731
})
732732

733+
it('should dedupe when re-fetched with queryClient.query while suspending', async () => {
734+
const key = queryKey()
735+
const renderStream = createRenderStream({ snapshotDOM: true })
736+
const queryFn = vi.fn().mockImplementation(async () => {
737+
await vi.advanceTimersByTimeAsync(10)
738+
return 'test'
739+
})
740+
741+
const options = {
742+
queryKey: key,
743+
queryFn,
744+
}
745+
746+
function MyComponent(props: { promise: Promise<string> }) {
747+
const data = React.use(props.promise)
748+
749+
return <>{data}</>
750+
}
751+
752+
function Loading() {
753+
return <>loading..</>
754+
}
755+
function Page() {
756+
const query = useQuery(options)
757+
758+
return (
759+
<div>
760+
<React.Suspense fallback={<Loading />}>
761+
<MyComponent promise={query.promise} />
762+
</React.Suspense>
763+
<button onClick={() => queryClient.query(options)}>fetch</button>
764+
</div>
765+
)
766+
}
767+
768+
const rendered = await renderStream.render(
769+
<QueryClientProvider client={queryClient}>
770+
<Page />
771+
</QueryClientProvider>,
772+
)
773+
774+
{
775+
const { withinDOM } = await renderStream.takeRender()
776+
withinDOM().getByText('loading..')
777+
}
778+
779+
rendered.getByText('fetch').click()
780+
781+
{
782+
const { withinDOM } = await renderStream.takeRender()
783+
withinDOM().getByText('test')
784+
}
785+
786+
expect(queryFn).toHaveBeenCalledOnce()
787+
})
788+
733789
it('should dedupe when re-fetched with refetchQueries while suspending', async () => {
734790
const key = queryKey()
735791
let count = 0

packages/react-query/src/types.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type {
55
DefinedInfiniteQueryObserverResult,
66
DefinedQueryObserverResult,
77
DistributiveOmit,
8-
FetchQueryOptions,
98
InfiniteQueryObserverOptions,
109
InfiniteQueryObserverResult,
1110
MutateFunction,
@@ -46,21 +45,6 @@ export interface UseBaseQueryOptions<
4645
subscribed?: boolean
4746
}
4847

49-
export interface UsePrefetchQueryOptions<
50-
TQueryFnData = unknown,
51-
TError = DefaultError,
52-
TData = TQueryFnData,
53-
TQueryKey extends QueryKey = QueryKey,
54-
> extends OmitKeyof<
55-
FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
56-
'queryFn'
57-
> {
58-
queryFn?: Exclude<
59-
FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>['queryFn'],
60-
SkipToken
61-
>
62-
}
63-
6448
export type AnyUseQueryOptions = UseQueryOptions<any, any, any, any>
6549
export interface UseQueryOptions<
6650
TQueryFnData = unknown,

packages/react-query/src/usePrefetchInfiniteQuery.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { noop } from '@tanstack/query-core'
12
import { useQueryClient } from './QueryClientProvider'
3+
24
import type {
35
DefaultError,
4-
FetchInfiniteQueryOptions,
6+
InfiniteQueryExecuteOptions,
57
QueryClient,
68
QueryKey,
79
} from '@tanstack/query-core'
@@ -13,7 +15,7 @@ export function usePrefetchInfiniteQuery<
1315
TQueryKey extends QueryKey = QueryKey,
1416
TPageParam = unknown,
1517
>(
16-
options: FetchInfiniteQueryOptions<
18+
options: InfiniteQueryExecuteOptions<
1719
TQueryFnData,
1820
TError,
1921
TData,
@@ -25,6 +27,6 @@ export function usePrefetchInfiniteQuery<
2527
const client = useQueryClient(queryClient)
2628

2729
if (!client.getQueryState(options.queryKey)) {
28-
client.prefetchInfiniteQuery(options)
30+
void client.infiniteQuery(options).then(noop).catch(noop)
2931
}
3032
}
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1+
import { noop } from '@tanstack/query-core'
12
import { useQueryClient } from './QueryClientProvider'
2-
import type { DefaultError, QueryClient, QueryKey } from '@tanstack/query-core'
3-
import type { UsePrefetchQueryOptions } from './types'
3+
4+
import type {
5+
DefaultError,
6+
QueryClient,
7+
QueryExecuteOptions,
8+
QueryKey,
9+
} from '@tanstack/query-core'
410

511
export function usePrefetchQuery<
612
TQueryFnData = unknown,
713
TError = DefaultError,
814
TData = TQueryFnData,
915
TQueryKey extends QueryKey = QueryKey,
1016
>(
11-
options: UsePrefetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
17+
options: QueryExecuteOptions<TQueryFnData, TError, TData, TQueryKey>,
1218
queryClient?: QueryClient,
1319
) {
1420
const client = useQueryClient(queryClient)
1521

1622
if (!client.getQueryState(options.queryKey)) {
17-
client.prefetchQuery(options)
23+
void client.query(options).then(noop).catch(noop)
1824
}
1925
}

0 commit comments

Comments
 (0)