diff --git a/docs/rtk-query/api/createApi.mdx b/docs/rtk-query/api/createApi.mdx index f21329bc41..30604b5e93 100644 --- a/docs/rtk-query/api/createApi.mdx +++ b/docs/rtk-query/api/createApi.mdx @@ -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 = ( +export type PageParamFunction = ( firstPage: DataType, allPages: Array, firstPageParam: PageParam, allPageParams: Array, + queryArg: QueryArg, ) => PageParam | undefined | null type InfiniteQueryCombinedArg = { @@ -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 + getNextPageParam: PageParamFunction /** * 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 + getPreviousPageParam?: PageParamFunction /** * If specified, only keep this many pages in cache at once. * If additional pages are fetched, older pages in the other diff --git a/docs/rtk-query/usage/infinite-queries.mdx b/docs/rtk-query/usage/infinite-queries.mdx index 2509913ef9..361fac13e1 100644 --- a/docs/rtk-query/usage/infinite-queries.mdx +++ b/docs/rtk-query/usage/infinite-queries.mdx @@ -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 = ( +export type PageParamFunction = ( currentPage: DataType, allPages: DataType[], currentPageParam: PageParam, allPageParams: PageParam[], + queryArg: QueryArg, ) => PageParam | undefined | null ``` @@ -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 @@ -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 }, diff --git a/packages/toolkit/src/query/core/apiState.ts b/packages/toolkit/src/query/core/apiState.ts index 85e6a8d010..af146a475f 100644 --- a/packages/toolkit/src/query/core/apiState.ts +++ b/packages/toolkit/src/query/core/apiState.ts @@ -25,14 +25,15 @@ export type RefetchConfigOptions = { refetchOnFocus: boolean } -export type PageParamFunction = ( +export type PageParamFunction = ( firstPage: DataType, allPages: Array, firstPageParam: PageParam, allPageParams: Array, + queryArg: QueryArg, ) => PageParam | undefined | null -export type InfiniteQueryConfigOptions = { +export type InfiniteQueryConfigOptions = { /** * The initial page parameter to use for the first page fetch. */ @@ -41,12 +42,12 @@ export type InfiniteQueryConfigOptions = { * 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 + getNextPageParam: PageParamFunction /** * 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 + getPreviousPageParam?: PageParamFunction /** * If specified, only keep this many pages in cache at once. * If additional pages are fetched, older pages in the other diff --git a/packages/toolkit/src/query/core/buildInitiate.ts b/packages/toolkit/src/query/core/buildInitiate.ts index 9d5f453a4b..f5af4d8667 100644 --- a/packages/toolkit/src/query/core/buildInitiate.ts +++ b/packages/toolkit/src/query/core/buildInitiate.ts @@ -79,7 +79,13 @@ export type StartInfiniteQueryActionCreatorOptions< param?: unknown } & Partial< Pick< - Partial, PageParamFrom>>, + Partial< + InfiniteQueryConfigOptions< + ResultTypeFrom, + PageParamFrom, + InfiniteQueryArgFrom + > + >, 'initialPageParam' > > diff --git a/packages/toolkit/src/query/core/buildSelectors.ts b/packages/toolkit/src/query/core/buildSelectors.ts index 106b157139..c6ff37191b 100644 --- a/packages/toolkit/src/query/core/buildSelectors.ts +++ b/packages/toolkit/src/query/core/buildSelectors.ts @@ -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, @@ -395,18 +397,20 @@ export function buildSelectors< } function getHasNextPage( - options: InfiniteQueryConfigOptions, + options: InfiniteQueryConfigOptions, data?: InfiniteData, + queryArg?: unknown, ): boolean { if (!data) return false - return getNextPageParam(options, data) != null + return getNextPageParam(options, data, queryArg) != null } function getHasPreviousPage( - options: InfiniteQueryConfigOptions, + options: InfiniteQueryConfigOptions, data?: InfiniteData, + queryArg?: unknown, ): boolean { if (!data || !options.getPreviousPageParam) return false - return getPreviousPageParam(options, data) != null + return getPreviousPageParam(options, data, queryArg) != null } } diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 20e4184dc6..048c98b9f3 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -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 { @@ -731,6 +735,7 @@ export function buildThunks< const param = getNextPageParam( infiniteQueryOptions, result.data as InfiniteData, + arg.originalArgs, ) result = await fetchPage( result.data as InfiniteData, @@ -1036,8 +1041,9 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".` } export function getNextPageParam( - options: InfiniteQueryConfigOptions, + options: InfiniteQueryConfigOptions, { pages, pageParams }: InfiniteData, + queryArg: unknown, ): unknown | undefined { const lastIndex = pages.length - 1 return options.getNextPageParam( @@ -1045,18 +1051,21 @@ export function getNextPageParam( pages, pageParams[lastIndex], pageParams, + queryArg, ) } export function getPreviousPageParam( - options: InfiniteQueryConfigOptions, + options: InfiniteQueryConfigOptions, { pages, pageParams }: InfiniteData, + queryArg: unknown, ): unknown | undefined { return options.getPreviousPageParam?.( pages[0], pages, pageParams[0], pageParams, + queryArg, ) } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index f881e78d88..39e3caf0a3 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -907,7 +907,11 @@ export interface InfiniteQueryExtraOptions< * ``` */ - infiniteQueryOptions: InfiniteQueryConfigOptions + infiniteQueryOptions: InfiniteQueryConfigOptions< + ResultType, + PageParam, + QueryArg + > /** * Can be provided to return a custom cache key value based on the query arguments. diff --git a/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts b/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts index 2ada1aef09..849356ed81 100644 --- a/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts +++ b/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts @@ -25,6 +25,7 @@ describe('Infinite queries', () => { allPages, lastPageParam, allPageParams, + queryArg, ) => { expectTypeOf(lastPage).toEqualTypeOf() @@ -34,6 +35,8 @@ describe('Infinite queries', () => { expectTypeOf(allPageParams).toEqualTypeOf() + expectTypeOf(queryArg).toBeString() + return lastPageParam + 1 }, }, diff --git a/packages/toolkit/src/query/tests/infiniteQueries.test.ts b/packages/toolkit/src/query/tests/infiniteQueries.test.ts index 450817b938..1325d135af 100644 --- a/packages/toolkit/src/query/tests/infiniteQueries.test.ts +++ b/packages/toolkit/src/query/tests/infiniteQueries.test.ts @@ -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 }, },