Skip to content
Merged
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
7 changes: 4 additions & 3 deletions docs/rtk-query/api/createApi.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,12 @@ Infinite query endpoints (defined with `build.infiniteQuery()`) are used to cach
For infinite query endpoints, there is a separation between the "query arg" used for the cache key, and the "page param" used to fetch a specific page. For example, a Pokemon API endpoint might have a string query arg like `"fire"` , but use a page number as the param to determine which page to fetch out of the results. The `query` and `queryFn` methods will receive a combined `{queryArg, pageParam}` object as the argument, rather than just the `queryArg` by itself.

```ts title="Infinite Query endpoint definition" no-transpile
export type PageParamFunction<DataType, PageParam> = (
export type PageParamFunction<DataType, PageParam, QueryArg> = (
firstPage: DataType,
allPages: Array<DataType>,
firstPageParam: PageParam,
allPageParams: Array<PageParam>,
queryArg: QueryArg,
) => PageParam | undefined | null

type InfiniteQueryCombinedArg<QueryArg, PageParam> = {
Expand Down Expand Up @@ -290,12 +291,12 @@ export type InfiniteQueryDefinition<
* This function is required to automatically get the next cursor for infinite queries.
* The result will also be used to determine the value of `hasNextPage`.
*/
getNextPageParam: PageParamFunction<DataType, PageParam>
getNextPageParam: PageParamFunction<DataType, PageParam, QueryArg>
/**
* This function can be set to automatically get the previous cursor for infinite queries.
* The result will also be used to determine the value of `hasPreviousPage`.
*/
getPreviousPageParam?: PageParamFunction<DataType, PageParam>
getPreviousPageParam?: PageParamFunction<DataType, PageParam, QueryArg>
/**
* If specified, only keep this many pages in cache at once.
* If additional pages are fetched, older pages in the other
Expand Down
15 changes: 12 additions & 3 deletions docs/rtk-query/usage/infinite-queries.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,12 @@ ensure the infinite query can properly fetch the next page of data. Also, `initi
`getNextPageParam` and `getPreviousPageParam` are user-defined, giving you flexibility to determine how those values are calculated:

```ts
export type PageParamFunction<DataType, PageParam> = (
export type PageParamFunction<DataType, PageParam, QueryArg> = (
currentPage: DataType,
allPages: DataType[],
currentPageParam: PageParam,
allPageParams: PageParam[],
queryArg: QueryArg,
) => PageParam | undefined | null
```

Expand All @@ -96,6 +97,8 @@ Since both actual page contents and page params are passed in, you can calculate

The "current" arguments will be either the last page for `getNextPageParam`, or the first page for `getPreviousPageParam`.

The list of arguments is the same as with React Query, but with the addition of `queryArg` at the end. (This is because React Query always has access to the query arg when you pass the options to its `useQuery` hook, but with RTK Query the endpoints are defined separately, so this makes the query arg accessible if you need it to calculate the page params.)

If there is no possible page to fetch in that direction, the callback should return `undefined`.

### Infinite Query Definition Example
Expand All @@ -119,14 +122,20 @@ const pokemonApi = createApi({
// Optionally limit the number of cached pages
maxPages: 3,
// Must provide a `getNextPageParam` function
getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) =>
lastPageParam + 1,
getNextPageParam: (
lastPage,
allPages,
lastPageParam,
allPageParams,
queryArg,
) => lastPageParam + 1,
// Optionally provide a `getPreviousPageParam` function
getPreviousPageParam: (
firstPage,
allPages,
firstPageParam,
allPageParams,
queryArg,
) => {
return firstPageParam > 0 ? firstPageParam - 1 : undefined
},
Expand Down
9 changes: 5 additions & 4 deletions packages/toolkit/src/query/core/apiState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ export type RefetchConfigOptions = {
refetchOnFocus: boolean
}

export type PageParamFunction<DataType, PageParam> = (
export type PageParamFunction<DataType, PageParam, QueryArg> = (
firstPage: DataType,
allPages: Array<DataType>,
firstPageParam: PageParam,
allPageParams: Array<PageParam>,
queryArg: QueryArg,
) => PageParam | undefined | null

export type InfiniteQueryConfigOptions<DataType, PageParam> = {
export type InfiniteQueryConfigOptions<DataType, PageParam, QueryArg> = {
/**
* The initial page parameter to use for the first page fetch.
*/
Expand All @@ -41,12 +42,12 @@ export type InfiniteQueryConfigOptions<DataType, PageParam> = {
* This function is required to automatically get the next cursor for infinite queries.
* The result will also be used to determine the value of `hasNextPage`.
*/
getNextPageParam: PageParamFunction<DataType, PageParam>
getNextPageParam: PageParamFunction<DataType, PageParam, QueryArg>
/**
* This function can be set to automatically get the previous cursor for infinite queries.
* The result will also be used to determine the value of `hasPreviousPage`.
*/
getPreviousPageParam?: PageParamFunction<DataType, PageParam>
getPreviousPageParam?: PageParamFunction<DataType, PageParam, QueryArg>
/**
* If specified, only keep this many pages in cache at once.
* If additional pages are fetched, older pages in the other
Expand Down
8 changes: 7 additions & 1 deletion packages/toolkit/src/query/core/buildInitiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ export type StartInfiniteQueryActionCreatorOptions<
param?: unknown
} & Partial<
Pick<
Partial<InfiniteQueryConfigOptions<ResultTypeFrom<D>, PageParamFrom<D>>>,
Partial<
InfiniteQueryConfigOptions<
ResultTypeFrom<D>,
PageParamFrom<D>,
InfiniteQueryArgFrom<D>
>
>,
'initialPageParam'
>
>
Expand Down
12 changes: 8 additions & 4 deletions packages/toolkit/src/query/core/buildSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,12 @@ export function buildSelectors<
hasNextPage: getHasNextPage(
infiniteQueryOptions,
stateWithRequestFlags.data,
stateWithRequestFlags.originalArgs,
),
hasPreviousPage: getHasPreviousPage(
infiniteQueryOptions,
stateWithRequestFlags.data,
stateWithRequestFlags.originalArgs,
),
isFetchingNextPage: isLoading && isForward,
isFetchingPreviousPage: isLoading && isBackward,
Expand Down Expand Up @@ -395,18 +397,20 @@ export function buildSelectors<
}

function getHasNextPage(
options: InfiniteQueryConfigOptions<any, any>,
options: InfiniteQueryConfigOptions<any, any, any>,
data?: InfiniteData<unknown, unknown>,
queryArg?: unknown,
): boolean {
if (!data) return false
return getNextPageParam(options, data) != null
return getNextPageParam(options, data, queryArg) != null
}

function getHasPreviousPage(
options: InfiniteQueryConfigOptions<any, any>,
options: InfiniteQueryConfigOptions<any, any, any>,
data?: InfiniteData<unknown, unknown>,
queryArg?: unknown,
): boolean {
if (!data || !options.getPreviousPageParam) return false
return getPreviousPageParam(options, data) != null
return getPreviousPageParam(options, data, queryArg) != null
}
}
15 changes: 12 additions & 3 deletions packages/toolkit/src/query/core/buildThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,11 @@ export function buildThunks<
if ('direction' in arg && arg.direction && existingData.pages.length) {
const previous = arg.direction === 'backward'
const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
const param = pageParamFn(infiniteQueryOptions, existingData)
const param = pageParamFn(
infiniteQueryOptions,
existingData,
arg.originalArgs,
)

result = await fetchPage(existingData, param, maxPages, previous)
} else {
Expand Down Expand Up @@ -731,6 +735,7 @@ export function buildThunks<
const param = getNextPageParam(
infiniteQueryOptions,
result.data as InfiniteData<unknown, unknown>,
arg.originalArgs,
)
result = await fetchPage(
result.data as InfiniteData<unknown, unknown>,
Expand Down Expand Up @@ -1036,27 +1041,31 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".`
}

export function getNextPageParam(
options: InfiniteQueryConfigOptions<unknown, unknown>,
options: InfiniteQueryConfigOptions<unknown, unknown, unknown>,
{ pages, pageParams }: InfiniteData<unknown, unknown>,
queryArg: unknown,
): unknown | undefined {
const lastIndex = pages.length - 1
return options.getNextPageParam(
pages[lastIndex],
pages,
pageParams[lastIndex],
pageParams,
queryArg,
)
}

export function getPreviousPageParam(
options: InfiniteQueryConfigOptions<unknown, unknown>,
options: InfiniteQueryConfigOptions<unknown, unknown, unknown>,
{ pages, pageParams }: InfiniteData<unknown, unknown>,
queryArg: unknown,
): unknown | undefined {
return options.getPreviousPageParam?.(
pages[0],
pages,
pageParams[0],
pageParams,
queryArg,
)
}

Expand Down
6 changes: 5 additions & 1 deletion packages/toolkit/src/query/endpointDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,11 @@ export interface InfiniteQueryExtraOptions<

* ```
*/
infiniteQueryOptions: InfiniteQueryConfigOptions<ResultType, PageParam>
infiniteQueryOptions: InfiniteQueryConfigOptions<
ResultType,
PageParam,
QueryArg
>

/**
* Can be provided to return a custom cache key value based on the query arguments.
Expand Down
3 changes: 3 additions & 0 deletions packages/toolkit/src/query/tests/infiniteQueries.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('Infinite queries', () => {
allPages,
lastPageParam,
allPageParams,
queryArg,
) => {
expectTypeOf(lastPage).toEqualTypeOf<Pokemon[]>()

Expand All @@ -34,6 +35,8 @@ describe('Infinite queries', () => {

expectTypeOf(allPageParams).toEqualTypeOf<number[]>()

expectTypeOf(queryArg).toBeString()

return lastPageParam + 1
},
},
Expand Down
8 changes: 7 additions & 1 deletion packages/toolkit/src/query/tests/infiniteQueries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ describe('Infinite queries', () => {
allPages,
lastPageParam,
allPageParams,
) => lastPageParam + 1,
queryArg,
) => {
expect(typeof queryArg).toBe('string')
return lastPageParam + 1
},
getPreviousPageParam: (
firstPage,
allPages,
firstPageParam,
allPageParams,
queryArg,
) => {
expect(typeof queryArg).toBe('string')
return firstPageParam > 0 ? firstPageParam - 1 : undefined
},
},
Expand Down
Loading