Skip to content

Commit 2751daf

Browse files
committed
Fix useInfiniteQuery hook types and trigger behavior
1 parent 80c9568 commit 2751daf

File tree

4 files changed

+92
-72
lines changed

4 files changed

+92
-72
lines changed

packages/toolkit/src/query/react/buildHooks.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,6 @@ export type LazyInfiniteQueryTrigger<
756756
*/
757757
(
758758
arg: QueryArgFrom<D>,
759-
data: InfiniteData<any, any>,
760759
direction: 'forward' | 'backwards',
761760
): InfiniteQueryActionCreatorResult<D>
762761
}
@@ -1013,8 +1012,8 @@ type UseInfiniteQueryStateBaseResult<
10131012
isFetchingNextPage: false
10141013
isFetchingPreviousPage: false
10151014

1016-
fetchNextPage: () => Promise<UseInfiniteQueryStateResult<D, D>>
1017-
fetchPreviousPage: () => Promise<UseInfiniteQueryStateResult<D, D>>
1015+
fetchNextPage: () => Promise<InfiniteQueryActionCreatorResult<D>>
1016+
fetchPreviousPage: () => Promise<InfiniteQueryActionCreatorResult<D>>
10181017
}
10191018

10201019
type UseInfiniteQueryStateDefaultResult<
@@ -1832,12 +1831,8 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
18321831
subscriptionOptionsRef.current = stableSubscriptionOptions
18331832
}, [stableSubscriptionOptions])
18341833

1835-
const trigger = useCallback(
1836-
function (
1837-
arg: any,
1838-
data: InfiniteData<any, any>,
1839-
direction: 'forward' | 'backwards',
1840-
) {
1834+
const trigger: LazyInfiniteQueryTrigger<any> = useCallback(
1835+
function (arg: unknown, direction: 'forward' | 'backwards') {
18411836
let promise: InfiniteQueryActionCreatorResult<any>
18421837

18431838
batch(() => {
@@ -1849,8 +1844,6 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
18491844
direction,
18501845
}),
18511846
)
1852-
1853-
// setArg(arg)
18541847
})
18551848

18561849
return promise!
@@ -1905,7 +1898,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
19051898
},
19061899
},
19071900
),
1908-
[select, stableArg, trigger],
1901+
[select, stableArg],
19091902
)
19101903

19111904
const querySelector: Selector<ApiRootState, any, [any]> = useMemo(
@@ -1958,8 +1951,6 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
19581951
},
19591952
)
19601953

1961-
const info = useMemo(() => ({ lastArg: arg }), [arg])
1962-
19631954
const {
19641955
data,
19651956
status,
@@ -1982,14 +1973,15 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
19821973
})
19831974

19841975
const fetchNextPage = useCallback(() => {
1985-
// if (!hasNextPage) return
1986-
return trigger(arg, queryStateResults.data, 'forward')
1987-
}, [trigger, hasNextPage, queryStateResults.data])
1976+
// TODO the hasNextPage bailout breaks things
1977+
//if (!hasNextPage) return
1978+
return trigger(arg, 'forward')
1979+
}, [trigger, arg])
19881980

19891981
const fetchPreviousPage = useCallback(() => {
1990-
if (!hasPreviousPage) return
1991-
return trigger(arg, queryStateResults.data, 'backwards')
1992-
}, [trigger, hasPreviousPage, queryStateResults.data])
1982+
//if (!hasPreviousPage) return
1983+
return trigger(arg, 'backwards')
1984+
}, [trigger, arg])
19931985

19941986
return useMemo(
19951987
() => ({ ...queryStateResults, fetchNextPage, fetchPreviousPage }),

packages/toolkit/src/query/tests/buildHooks.test.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ describe('hooks tests', () => {
796796
allPageParams,
797797
) => lastPageParam + 1,
798798
},
799-
query(pageParam = 0) {
799+
query(pageParam) {
800800
return `https://example.com/listItems?page=${pageParam}`
801801
},
802802
}),
@@ -810,13 +810,12 @@ describe('hooks tests', () => {
810810
const checkNumQueries = (count: number) => {
811811
const cacheEntries = Object.keys(storeRef.store.getState().api.queries)
812812
const queries = cacheEntries.length
813-
console.log('queries', queries)
814-
console.log(storeRef.store.getState().api.queries)
813+
console.log('queries', queries, storeRef.store.getState().api.queries)
815814

816815
expect(queries).toBe(count)
817816
}
818817

819-
function User() {
818+
function PokemonList() {
820819
const { data, isFetching, isUninitialized, fetchNextPage } =
821820
pokemonApi.endpoints.getInfinitePokemon.useInfiniteQuery('a', {
822821
initialPageParam: 0,
@@ -829,6 +828,11 @@ describe('hooks tests', () => {
829828
) => lastPageParam + 1,
830829
})
831830

831+
const handleClick = async () => {
832+
const promise = fetchNextPage()
833+
const res = await promise
834+
}
835+
832836
return (
833837
<div>
834838
<div data-testid="isUninitialized">{String(isUninitialized)}</div>
@@ -838,14 +842,14 @@ describe('hooks tests', () => {
838842
<div key={i}>{JSON.stringify(page)}</div>
839843
))}
840844
</div>
841-
<button data-testid="nextPage" onClick={() => fetchNextPage()}>
845+
<button data-testid="nextPage" onClick={() => handleClick()}>
842846
nextPage
843847
</button>
844848
</div>
845849
)
846850
}
847851

848-
render(<User />, { wrapper: storeRef.wrapper })
852+
render(<PokemonList />, { wrapper: storeRef.wrapper })
849853
expect(screen.getByTestId('data').textContent).toBe('')
850854
checkNumQueries(1)
851855

@@ -855,7 +859,12 @@ describe('hooks tests', () => {
855859
await waitFor(() =>
856860
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
857861
)
858-
fireEvent.click(screen.getByTestId('nextPage'))
862+
act(() => {
863+
fireEvent.click(screen.getByTestId('nextPage'))
864+
})
865+
await waitFor(() =>
866+
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
867+
)
859868
checkNumQueries(1)
860869
await waitFor(() =>
861870
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
@@ -1505,7 +1514,7 @@ describe('hooks tests', () => {
15051514

15061515
setDataFromTrigger(res) // adding client side state here will cause stale data
15071516
} catch (error) {
1508-
console.error(error)
1517+
console.error('Error handling increment trigger', error)
15091518
}
15101519
}
15111520

@@ -1515,7 +1524,7 @@ describe('hooks tests', () => {
15151524
// Force the lazy trigger to refetch
15161525
await handleLoad()
15171526
} catch (error) {
1518-
console.error(error)
1527+
console.error('Error handling mutate trigger', error)
15191528
}
15201529
}
15211530

packages/toolkit/src/query/tests/infiniteQueries.test-d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ describe('Infinite queries', () => {
100100
expectTypeOf(currentData.pages).toEqualTypeOf<Pokemon[][]>()
101101
expectTypeOf(currentData.pageParams).toEqualTypeOf<number[]>()
102102
}
103+
104+
const handleClick = async () => {
105+
const res = await fetchNextPage()
106+
107+
if (res.status === QueryStatus.fulfilled) {
108+
expectTypeOf(res.data.pages).toEqualTypeOf<Pokemon[][]>()
109+
expectTypeOf(res.data.pageParams).toEqualTypeOf<number[]>()
110+
}
111+
}
103112
}
104113
})
105114
})

packages/toolkit/src/query/tests/infiniteQueries.test.ts

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { configureStore, isAllOf } from '@reduxjs/toolkit'
2-
import { renderHook, waitFor } from '@testing-library/react'
2+
import {
3+
act,
4+
fireEvent,
5+
render,
6+
renderHook,
7+
screen,
8+
waitFor,
9+
} from '@testing-library/react'
10+
import userEvent from '@testing-library/user-event'
311
import { HttpResponse, http } from 'msw'
412
import util from 'util'
513
import {
@@ -17,57 +25,59 @@ import type { BaseQueryApi } from '../baseQueryTypes'
1725
import { server } from '@internal/query/tests/mocks/server'
1826

1927
describe('Infinite queries', () => {
20-
beforeEach(() => {
21-
server.resetHandlers()
22-
})
28+
type Pokemon = {
29+
id: string
30+
name: string
31+
}
2332

24-
test('Basic infinite query behavior', async () => {
25-
type Pokemon = {
26-
id: string
27-
name: string
28-
}
33+
server.use(
34+
http.get('https://example.com/listItems', ({ request }) => {
35+
const url = new URL(request.url)
36+
const pageString = url.searchParams.get('page')
37+
const pageNum = parseInt(pageString || '0')
2938

30-
server.use(
31-
http.get('https://example.com/listItems', ({ request }) => {
32-
const url = new URL(request.url)
33-
const pageString = url.searchParams.get('page')
34-
const pageNum = parseInt(pageString || '0')
39+
const results: Pokemon[] = [
40+
{ id: `${pageNum}`, name: `Pokemon ${pageNum}` },
41+
]
42+
return HttpResponse.json(results)
43+
}),
44+
)
3545

36-
const results: Pokemon[] = [
37-
{ id: `${pageNum}`, name: `Pokemon ${pageNum}` },
38-
]
39-
return HttpResponse.json(results)
46+
const pokemonApi = createApi({
47+
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
48+
endpoints: (builder) => ({
49+
// GOAL: Specify both the query arg (for cache key serialization)
50+
// and the page param type (for feeding into the query URL)
51+
getInfinitePokemon: builder.infiniteQuery<Pokemon[], string, number>({
52+
infiniteQueryOptions: {
53+
initialPageParam: 0,
54+
getNextPageParam: (
55+
lastPage,
56+
allPages,
57+
// Page param type should be `number`
58+
lastPageParam,
59+
allPageParams,
60+
) => lastPageParam + 1,
61+
},
62+
// Actual query arg type should be `number`
63+
query(pageParam) {
64+
return `https://example.com/listItems?page=${pageParam}`
65+
},
4066
}),
41-
)
67+
}),
68+
})
4269

43-
const pokemonApi = createApi({
44-
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
45-
endpoints: (builder) => ({
46-
// GOAL: Specify both the query arg (for cache key serialization)
47-
// and the page param type (for feeding into the query URL)
48-
getInfinitePokemon: builder.infiniteQuery<Pokemon[], string, number>({
49-
infiniteQueryOptions: {
50-
initialPageParam: 0,
51-
getNextPageParam: (
52-
lastPage,
53-
allPages,
54-
// Page param type should be `number`
55-
lastPageParam,
56-
allPageParams,
57-
) => lastPageParam + 1,
58-
},
59-
// Actual query arg type should be `number`
60-
query(pageParam) {
61-
return `https://example.com/listItems?page=${pageParam}`
62-
},
63-
}),
64-
}),
65-
})
70+
let storeRef = setupApiStore(pokemonApi, undefined, {
71+
withoutTestLifecycles: true,
72+
})
6673

67-
const storeRef = setupApiStore(pokemonApi, undefined, {
74+
beforeEach(() => {
75+
storeRef = setupApiStore(pokemonApi, undefined, {
6876
withoutTestLifecycles: true,
6977
})
78+
})
7079

80+
test('Basic infinite query behavior', async () => {
7181
const res = storeRef.store.dispatch(
7282
// Should be `arg: string`
7383
pokemonApi.endpoints.getInfinitePokemon.initiate('fire', {}),

0 commit comments

Comments
 (0)