Skip to content

Commit 993024c

Browse files
committed
Fix useInfiniteQuery hook types and trigger behavior
1 parent 7870a64 commit 993024c

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
@@ -788,7 +788,6 @@ export type LazyInfiniteQueryTrigger<
788788
*/
789789
(
790790
arg: QueryArgFrom<D>,
791-
data: InfiniteData<any, any>,
792791
direction: 'forward' | 'backwards',
793792
): InfiniteQueryActionCreatorResult<D>
794793
}
@@ -1045,8 +1044,8 @@ type UseInfiniteQueryStateBaseResult<
10451044
isFetchingNextPage: false
10461045
isFetchingPreviousPage: false
10471046

1048-
fetchNextPage: () => Promise<UseInfiniteQueryStateResult<D, D>>
1049-
fetchPreviousPage: () => Promise<UseInfiniteQueryStateResult<D, D>>
1047+
fetchNextPage: () => Promise<InfiniteQueryActionCreatorResult<D>>
1048+
fetchPreviousPage: () => Promise<InfiniteQueryActionCreatorResult<D>>
10501049
}
10511050

10521051
type UseInfiniteQueryStateDefaultResult<
@@ -1884,12 +1883,8 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
18841883
subscriptionOptionsRef.current = stableSubscriptionOptions
18851884
}, [stableSubscriptionOptions])
18861885

1887-
const trigger = useCallback(
1888-
function (
1889-
arg: any,
1890-
data: InfiniteData<any, any>,
1891-
direction: 'forward' | 'backwards',
1892-
) {
1886+
const trigger: LazyInfiniteQueryTrigger<any> = useCallback(
1887+
function (arg: unknown, direction: 'forward' | 'backwards') {
18931888
let promise: InfiniteQueryActionCreatorResult<any>
18941889

18951890
batch(() => {
@@ -1901,8 +1896,6 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
19011896
direction,
19021897
}),
19031898
)
1904-
1905-
// setArg(arg)
19061899
})
19071900

19081901
return promise!
@@ -1957,7 +1950,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
19571950
},
19581951
},
19591952
),
1960-
[select, stableArg, trigger],
1953+
[select, stableArg],
19611954
)
19621955

19631956
const querySelector: Selector<ApiRootState, any, [any]> = useMemo(
@@ -2010,8 +2003,6 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
20102003
},
20112004
)
20122005

2013-
const info = useMemo(() => ({ lastArg: arg }), [arg])
2014-
20152006
const {
20162007
data,
20172008
status,
@@ -2034,14 +2025,15 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
20342025
})
20352026

20362027
const fetchNextPage = useCallback(() => {
2037-
// if (!hasNextPage) return
2038-
return trigger(arg, queryStateResults.data, 'forward')
2039-
}, [trigger, hasNextPage, queryStateResults.data])
2028+
// TODO the hasNextPage bailout breaks things
2029+
//if (!hasNextPage) return
2030+
return trigger(arg, 'forward')
2031+
}, [trigger, arg])
20402032

20412033
const fetchPreviousPage = useCallback(() => {
2042-
if (!hasPreviousPage) return
2043-
return trigger(arg, queryStateResults.data, 'backwards')
2044-
}, [trigger, hasPreviousPage, queryStateResults.data])
2034+
//if (!hasPreviousPage) return
2035+
return trigger(arg, 'backwards')
2036+
}, [trigger, arg])
20452037

20462038
return useMemo(
20472039
() => ({ ...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
@@ -949,7 +949,7 @@ describe('hooks tests', () => {
949949
allPageParams,
950950
) => lastPageParam + 1,
951951
},
952-
query(pageParam = 0) {
952+
query(pageParam) {
953953
return `https://example.com/listItems?page=${pageParam}`
954954
},
955955
}),
@@ -963,13 +963,12 @@ describe('hooks tests', () => {
963963
const checkNumQueries = (count: number) => {
964964
const cacheEntries = Object.keys(storeRef.store.getState().api.queries)
965965
const queries = cacheEntries.length
966-
console.log('queries', queries)
967-
console.log(storeRef.store.getState().api.queries)
966+
console.log('queries', queries, storeRef.store.getState().api.queries)
968967

969968
expect(queries).toBe(count)
970969
}
971970

972-
function User() {
971+
function PokemonList() {
973972
const { data, isFetching, isUninitialized, fetchNextPage } =
974973
pokemonApi.endpoints.getInfinitePokemon.useInfiniteQuery('a', {
975974
initialPageParam: 0,
@@ -982,6 +981,11 @@ describe('hooks tests', () => {
982981
) => lastPageParam + 1,
983982
})
984983

984+
const handleClick = async () => {
985+
const promise = fetchNextPage()
986+
const res = await promise
987+
}
988+
985989
return (
986990
<div>
987991
<div data-testid="isUninitialized">{String(isUninitialized)}</div>
@@ -991,14 +995,14 @@ describe('hooks tests', () => {
991995
<div key={i}>{JSON.stringify(page)}</div>
992996
))}
993997
</div>
994-
<button data-testid="nextPage" onClick={() => fetchNextPage()}>
998+
<button data-testid="nextPage" onClick={() => handleClick()}>
995999
nextPage
9961000
</button>
9971001
</div>
9981002
)
9991003
}
10001004

1001-
render(<User />, { wrapper: storeRef.wrapper })
1005+
render(<PokemonList />, { wrapper: storeRef.wrapper })
10021006
expect(screen.getByTestId('data').textContent).toBe('')
10031007
checkNumQueries(1)
10041008

@@ -1008,7 +1012,12 @@ describe('hooks tests', () => {
10081012
await waitFor(() =>
10091013
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
10101014
)
1011-
fireEvent.click(screen.getByTestId('nextPage'))
1015+
act(() => {
1016+
fireEvent.click(screen.getByTestId('nextPage'))
1017+
})
1018+
await waitFor(() =>
1019+
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
1020+
)
10121021
checkNumQueries(1)
10131022
await waitFor(() =>
10141023
expect(screen.getByTestId('isFetching').textContent).toBe('false'),
@@ -1656,7 +1665,7 @@ describe('hooks tests', () => {
16561665

16571666
setDataFromTrigger(res) // adding client side state here will cause stale data
16581667
} catch (error) {
1659-
console.error(error)
1668+
console.error('Error handling increment trigger', error)
16601669
}
16611670
}
16621671

@@ -1666,7 +1675,7 @@ describe('hooks tests', () => {
16661675
// Force the lazy trigger to refetch
16671676
await handleLoad()
16681677
} catch (error) {
1669-
console.error(error)
1678+
console.error('Error handling mutate trigger', error)
16701679
}
16711680
}
16721681

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)