Skip to content

Commit cc234f4

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

10 files changed

Lines changed: 184 additions & 63 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: 65 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,44 @@ 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+
})
93+
it('should work when passed to infiniteQuery', async () => {
94+
const options = infiniteQueryOptions({
95+
queryKey: ['key'],
96+
queryFn: () => Promise.resolve('string'),
97+
getNextPageParam: () => 1,
98+
initialPageParam: 1,
99+
})
100+
101+
const data = await new QueryClient().infiniteQuery(options)
102+
103+
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
104+
})
105+
it('should work when passed to infiniteQuery with select', async () => {
106+
const options = infiniteQueryOptions({
107+
queryKey: ['key'],
108+
queryFn: () => Promise.resolve('string'),
109+
getNextPageParam: () => 1,
110+
initialPageParam: 1,
111+
select: (data) => data.pages,
112+
})
113+
114+
const data = await new QueryClient().infiniteQuery(options)
115+
116+
expectTypeOf(data).toEqualTypeOf<Array<string>>()
117+
})
66118
it('should work when passed to fetchInfiniteQuery', async () => {
67119
const options = infiniteQueryOptions({
68120
queryKey: queryKey(),
@@ -75,6 +127,19 @@ describe('infiniteQueryOptions', () => {
75127

76128
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
77129
})
130+
it('should ignore select when passed to fetchInfiniteQuery', async () => {
131+
const options = infiniteQueryOptions({
132+
queryKey: ['key'],
133+
queryFn: () => Promise.resolve('string'),
134+
getNextPageParam: () => 1,
135+
initialPageParam: 1,
136+
select: (data) => data.pages,
137+
})
138+
139+
const data = await new QueryClient().fetchInfiniteQuery(options)
140+
141+
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
142+
})
78143
it('should tag the queryKey with the result type of the QueryFn', () => {
79144
const { queryKey: tagged } = infiniteQueryOptions({
80145
queryKey: queryKey(),

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,15 @@ describe('queryOptions', () => {
5757
const { data } = useSuspenseQuery(options)
5858
expectTypeOf(data).toEqualTypeOf<number>()
5959
})
60+
it('should work when passed to query', async () => {
61+
const options = queryOptions({
62+
queryKey: ['key'],
63+
queryFn: () => Promise.resolve(5),
64+
})
6065

66+
const data = await new QueryClient().query(options)
67+
expectTypeOf(data).toEqualTypeOf<number>()
68+
})
6169
it('should work when passed to fetchQuery', async () => {
6270
const options = queryOptions({
6371
queryKey: queryKey(),
@@ -67,6 +75,26 @@ describe('queryOptions', () => {
6775
const data = await new QueryClient().fetchQuery(options)
6876
expectTypeOf(data).toEqualTypeOf<number>()
6977
})
78+
it('should work when passed to query with select', async () => {
79+
const options = queryOptions({
80+
queryKey: ['key'],
81+
queryFn: () => Promise.resolve(5),
82+
select: (data) => data.toString(),
83+
})
84+
85+
const data = await new QueryClient().query(options)
86+
expectTypeOf(data).toEqualTypeOf<string>()
87+
})
88+
it('should ignore select when passed to fetchQuery', async () => {
89+
const options = queryOptions({
90+
queryKey: ['key'],
91+
queryFn: () => Promise.resolve(5),
92+
select: (data) => data.toString(),
93+
})
94+
95+
const data = await new QueryClient().fetchQuery(options)
96+
expectTypeOf(data).toEqualTypeOf<number>()
97+
})
7098
it('should work when passed to useQueries', () => {
7199
const options = queryOptions({
72100
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({

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

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('usePrefetchInfiniteQuery', () => {
2424
)
2525
})
2626

27-
it('should not allow refetchInterval, enabled or throwOnError options', () => {
27+
it('should not allow refetchInterval or throwOnError options', () => {
2828
assertType(
2929
usePrefetchInfiniteQuery({
3030
queryKey: queryKey(),
@@ -36,17 +36,6 @@ describe('usePrefetchInfiniteQuery', () => {
3636
}),
3737
)
3838

39-
assertType(
40-
usePrefetchInfiniteQuery({
41-
queryKey: queryKey(),
42-
queryFn: () => Promise.resolve(5),
43-
initialPageParam: 1,
44-
getNextPageParam: () => 1,
45-
// @ts-expect-error TS2353
46-
enabled: true,
47-
}),
48-
)
49-
5039
assertType(
5140
usePrefetchInfiniteQuery({
5241
queryKey: queryKey(),
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)