Skip to content

Conversation

@visz11
Copy link
Collaborator

@visz11 visz11 commented Nov 21, 2025

CodeAnt-AI Description

Allow imperative infinite queries with manual page params

What Changed

  • fetchNextPage and fetchPreviousPage now pass any provided pageParam directly to the fetch so manually supplied cursors control each page and refetch replays the same params
  • Infinite queries can omit getNextPageParam, but when they do callers must supply pageParam to move forward or backward while the option remains optional when a cursor function exists
  • Added type coverage that aligns the runtime requirement with the observable API so developers immediately see when manual params are required

Impact

✅ Manual paging for infinite lists
✅ Consistent refetch of previously loaded pages
✅ Clearer manual pagination requirements

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features

    • fetchNextPage() and fetchPreviousPage() now accept an explicit pageParam parameter for manual pagination control.
    • getNextPageParam is now optional, enabling manual page parameter management without required callback functions.
  • Tests

    • Added test coverage for explicit page parameter handling in infinite queries.
    • Added type-level tests for fetch method parameter validation.

✏️ Tip: You can customize this high-level summary in your review settings.

let's bring back imperative infinite queries, but only allow them in an all-or-nothing mode, dependent on if `getNextPageParam` has been passed
@codeant-ai
Copy link

codeant-ai bot commented Nov 21, 2025

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@visz11
Copy link
Collaborator Author

visz11 commented Nov 21, 2025

@refacto-visz

@gemini-code-assist
Copy link

Summary of Changes

Hello @visz11, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the flexibility of infinite queries by allowing developers to imperatively specify the pageParam when requesting the next or previous page. This change is particularly useful for scenarios where the application needs fine-grained control over pagination logic, or when getNextPageParam is not defined in the query options. The update includes adjustments to the core query behavior, observer methods, and type definitions to ensure robust and type-safe operation of this new functionality.

Highlights

  • Imperative PageParam Control: Introduced the ability to explicitly pass a pageParam to fetchNextPage and fetchPreviousPage methods for infinite queries, allowing for manual control over pagination.
  • Optional getNextPageParam: The getNextPageParam option in InfiniteQueryPageParamsOptions is now optional, enabling use cases where page parameters are managed externally or imperatively.
  • Type Safety Enhancements: Added type definition tests to ensure that pageParam is conditionally allowed or required in fetchNextPage and fetchPreviousPage based on whether getNextPageParam is defined in the query options.
  • Refetch Behavior Update: Modified the infiniteQueryBehavior to correctly handle and prioritize manually provided pageParam values during subsequent fetches and refetches.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Nov 21, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The changes enable explicit pageParam control in infinite queries by making getNextPageParam optional and adding support for passing pageParam through fetchNextPage/fetchPreviousPage methods. Tests verify this behavior with duplicated coverage, and type definitions are updated accordingly.

Changes

Cohort / File(s) Summary
Type & Interface Updates
packages/query-core/src/types.ts, packages/query-core/src/query.ts
Made getNextPageParam optional in InfiniteQueryPageParamsOptions. Extended FetchMeta.fetchMore to include optional pageParam field.
Core Implementation
packages/query-core/src/infiniteQueryObserver.ts
Updated fetchNextPage and fetchPreviousPage signatures to destructure and pass pageParam through to meta.fetchMore.
Infinite Query Behavior
packages/query-core/src/infiniteQueryBehavior.ts
Added logic to use explicit pageParam from fetchMore object when provided; implemented optional chaining for getNextPageParam calls; expanded initial param selection for page fetching.
Test Coverage
packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx
Added test suite validating explicit pageParam navigation with fetchNextPage and fetchPreviousPage; suite is duplicated later in file.
Type-Level Tests
packages/query-core/src/__tests__/infiniteQueryObserver.test-d.tsx
Added type assertions for fetchNextPage and fetchPreviousPage parameter shapes based on presence of getNextPageParam.

Sequence Diagram

sequenceDiagram
    actor User
    participant Observer as InfiniteQueryObserver
    participant Behavior as infiniteQueryBehavior
    participant Query as Query Engine

    User->>Observer: fetchNextPage({ pageParam: 5 })
    Observer->>Behavior: fetch with meta.fetchMore = { direction: 'forward', pageParam: 5 }
    alt pageParam provided in meta.fetchMore
        Behavior->>Behavior: Use explicit pageParam: 5
    else pageParam not provided
        Behavior->>Behavior: Compute nextPageParam via getNextPageParam()
    end
    Behavior->>Query: Execute queryFn with pageParam: 5, direction: 'forward'
    Query-->>Behavior: Return data for page 5
    Behavior-->>Observer: Update pages and pageParams
    Observer-->>User: Return InfiniteQueryObserverResult

    User->>Observer: fetchPreviousPage({ pageParam: -1 })
    Observer->>Behavior: fetch with meta.fetchMore = { direction: 'backward', pageParam: -1 }
    Behavior->>Behavior: Use explicit pageParam: -1
    Behavior->>Query: Execute queryFn with pageParam: -1, direction: 'backward'
    Query-->>Behavior: Return data for page -1
    Behavior-->>Observer: Update pages and pageParams
    Observer-->>User: Return InfiniteQueryObserverResult
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Duplicated test block: The identical test suite in infiniteQueryBehavior.test.tsx should be verified—determine if intentional or oversight
  • Optional chaining logic: Review infiniteQueryBehavior.ts carefully for correct optional chaining and fallback param selection, especially in the getNextPageParam invocation and page fetch initialization
  • Signature integration: Verify fetchNextPage/fetchPreviousPage signature changes integrate correctly with meta.fetchMore propagation and downstream behavior consumption

Poem

🐰 A pageParam now hops freely,
No longer bound by computed bounds,
When direction is clear and params explicit,
The infinite scroll finds surer ground,
Though tests duplicate with bunny-eared glee! 🔄✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Clone feature/imperative infinite queries' directly relates to the core changes in the PR, which implement imperative-style fetch control for infinite queries through explicit pageParam overrides and optional getNextPageParam.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch clone-feature/imperative-infinite-queries

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@refacto-visz
Copy link

refacto-visz bot commented Nov 21, 2025

feat: Allow imperative page param for infinite queries

TL;DR: This change makes getNextPageParam optional for infinite queries, allowing developers to manually provide a pageParam when calling fetchNextPage or fetchPreviousPage.


Refacto PR Summary

This pull request introduces a significant enhancement to infinite queries by enabling an imperative fetching model. Previously, infinite queries required getNextPageParam and getPreviousPageParam functions to automatically determine the cursor for subsequent pages. This change makes those functions optional.

If getNextPageParam is not provided, developers can now manually pass a pageParam directly to the fetchNextPage and fetchPreviousPage methods. The core query behavior has been updated to prioritize this explicitly passed pageParam. Furthermore, these manually provided page parameters are stored and correctly reused during a full refetch, ensuring data consistency. TypeScript definitions have been updated to enforce this new API contract, allowing pageParam only when getNextPageParam is absent, thus improving type safety and developer experience.

Change Highlights

Click to expand
  • packages/query-core/src/infiniteQueryObserver.ts: The fetchNextPage and fetchPreviousPage methods now accept a pageParam in their options object, which is passed down to the core fetching logic.
  • packages/query-core/src/infiniteQueryBehavior.ts: The onFetch logic now checks for a pageParam within the fetch metadata. If present, it's used directly for fetching the page, bypassing the need for getNextPageParam.
  • packages/query-core/src/types.ts: The getNextPageParam property on InfiniteQueryPageParamsOptions is now optional, officially supporting the new imperative API.
  • packages/query-core/src/query.ts: The FetchMeta interface is updated to include the optional pageParam on the fetchMore object.
  • packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx: A comprehensive test case was added to validate the new behavior, including fetching next/previous pages imperatively and ensuring refetch works correctly with the stored page params.
  • packages/query-core/src/__tests__/infiniteQueryObserver.test-d.tsx: TypeScript definition tests were added to ensure the pageParam option is only available on fetchNextPage/fetchPreviousPage when getNextPageParam is not defined.

Sequence Diagram

sequenceDiagram
    participant C as Component
    participant O as InfiniteQueryObserver
    participant B as InfiniteQueryBehavior
    participant QF as queryFn

    C->>O: fetchNextPage({ pageParam: 2 })
    Note over O: getNextPageParam is not defined
    O->>B: fetch(meta: { fetchMore: { direction: 'forward', pageParam: 2 } })
    B->>B: Prioritize explicit pageParam over getNextPageParam
    B->>QF: Execute with { pageParam: 2 }
    QF-->>B: Return page data for page 2
    B-->>O: New state with appended page
    O-->>C: Notify with updated data { pages: [page1, page2] }
Loading

Testing Guide

Click to expand
  1. Setup: Create an infinite query using useInfiniteQuery but do not provide a getNextPageParam function. Set initialPageParam to 0.
  2. Initial Fetch: Verify that the query successfully fetches the first page using pageParam: 0.
  3. Imperative Fetch Next: Call fetchNextPage({ pageParam: 1 }). Check that the queryFn is called with pageParam: 1 and the new data is appended to the data.pages array.
  4. Imperative Fetch Previous: Call fetchPreviousPage({ pageParam: -1 }). Verify the queryFn is called with pageParam: -1 and the new data is prepended. The final data should be pages: [-1, 0, 1].
  5. Refetch: Call refetch(). Observe that the query function is called three times, once for each of the stored page params (-1, 0, and 1), correctly refetching all existing data.

@codeant-ai codeant-ai bot added the size:L This PR changes 100-499 lines, ignoring generated files label Nov 21, 2025
@refacto-visz
Copy link

refacto-visz bot commented Nov 21, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

@codeant-ai
Copy link

codeant-ai bot commented Nov 21, 2025

CodeAnt AI finished reviewing your PR.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an imperative API for infinite queries, allowing pageParam to be passed directly to fetchNextPage and fetchPreviousPage. This is a great feature for pagination patterns where the next page's identifier isn't easily derived. The changes are well-implemented across the core logic, types, and are accompanied by good tests. I've found one critical issue in the refetch logic for imperatively-fetched pages, which could lead to incorrect data being refetched. My review includes a suggested fix for this issue.

Comment on lines 102 to 105
const param =
currentPage === 0
? (oldPageParams[0] ?? options.initialPageParam)
currentPage === 0 || !options.getNextPageParam
? (oldPageParams[currentPage] ?? options.initialPageParam)
: getNextPageParam(options, result)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The logic for determining the param for refetching seems to have a bug when getNextPageParam is not provided. For subsequent pages (currentPage > 0), if oldPageParams[currentPage] is undefined or null, it incorrectly falls back to options.initialPageParam. This would cause a refetch with the wrong page parameter. For example, if pageParams were [1, undefined], a refetch would request pages for 1 and then for initialPageParam, instead of 1 and undefined.

The fallback to initialPageParam should only happen for the very first page (currentPage === 0) when there are no previous page params.

            const param =
              currentPage === 0
                ? oldPageParams[0] ?? options.initialPageParam
                : !options.getNextPageParam
                ? oldPageParams[currentPage]
                : getNextPageParam(options, result)

@refacto-visz
Copy link

refacto-visz bot commented Nov 21, 2025

Code Review: Imperative Infinite Query Enhancements

👍 Well Done
Comprehensive Test Coverage

The new feature is well-tested, including unit tests for behavior and dedicated type-level tests for API contract correctness, increasing confidence in the changes.

Robust API Design and Typing

Excellent use of conditional types and type-definition tests to enforce the new API contract for imperative fetching, preventing misuse and guiding developers.

Correct Refetch Behavior

The refactoring of the refetch logic to correctly use the page parameter for each page improves the correctness and robustness of the query refetching mechanism.

📁 Selected files for review (6)
  • packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx
  • packages/query-core/src/__tests__/infiniteQueryObserver.test-d.tsx
  • packages/query-core/src/infiniteQueryBehavior.ts
  • packages/query-core/src/infiniteQueryObserver.ts
  • packages/query-core/src/query.ts
  • packages/query-core/src/types.ts
🎯 Custom Instructions
✅ Applied Instructions
Organization Guidelines
  • Use feature flags for new functionality and include a clear rollback plan.
  • Very critical to consider apply pagination to queries
  • Follow the company security checklist:
    • No hard-coded secrets or credentials.
    • Validate all external inputs.
    • Use parameterized queries for DB access.

Scope: All files

📝 Additional Comments
packages/query-core/src/types.ts (1)
Increased API Complexity from Dual-Mode Behavior

Making getNextPageParam optional creates two distinct modes for infinite queries (automatic vs. imperative). While powerful, this increases the API's complexity and cognitive load for developers. It is suggested to ensure this dual-mode behavior is exceptionally well-documented to prevent confusion and maintain usability.

Standards:

  • Maintainability-Quality-API-Design

Comment on lines +127 to 150
fetchNextPage({ pageParam, ...options }: FetchNextPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'forward' },
fetchMore: { direction: 'forward', pageParam },
},
})
}

fetchPreviousPage(
options?: FetchPreviousPageOptions,
): Promise<InfiniteQueryObserverResult<TData, TError>> {
fetchPreviousPage({
pageParam,
...options
}: FetchPreviousPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'backward' },
fetchMore: { direction: 'backward', pageParam },
},
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New Feature Lacks Required Feature Flag

This change introduces a significant new feature (imperative page parameters) without being gated by a feature flag. This violates the organization guideline for new functionality, which is crucial for controlled rollouts and ensuring a clear rollback plan. The new API surface should be conditionally enabled via a feature flag.

  fetchNextPage(
    options?: FetchNextPageOptions,
  ): Promise<InfiniteQueryObserverResult<TData, TError>> {
    return this.fetch({
      ...options,
      meta: {
        fetchMore: { direction: 'forward' },
      },
    })
  }

  fetchPreviousPage(
    options?: FetchPreviousPageOptions,
  ): Promise<InfiniteQueryObserverResult<TData, TError>> {
    return this.fetch({
      ...options,
      meta: {
        fetchMore: { direction: 'backward' },
      },
    })
  }
Commitable Suggestion
Suggested change
fetchNextPage({ pageParam, ...options }: FetchNextPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'forward' },
fetchMore: { direction: 'forward', pageParam },
},
})
}
fetchPreviousPage(
options?: FetchPreviousPageOptions,
): Promise<InfiniteQueryObserverResult<TData, TError>> {
fetchPreviousPage({
pageParam,
...options
}: FetchPreviousPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'backward' },
fetchMore: { direction: 'backward', pageParam },
},
})
}
fetchNextPage(
options?: FetchNextPageOptions,
): Promise<InfiniteQueryObserverResult<TData, TError>> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'forward' },
},
})
}
fetchPreviousPage(
options?: FetchPreviousPageOptions,
): Promise<InfiniteQueryObserverResult<TData, TError>> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'backward' },
},
})
}
Standards
  • Org-Guideline-Use feature flags for new functionality and include a clear rollback plan.

getNextPageParam?: GetNextPageParamFunction<TPageParam, TQueryFnData>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Contract Changed Without Feature Flag

A significant new feature allowing imperative page fetching has been introduced by making getNextPageParam optional. This changes a core API contract without being placed behind a feature flag, violating company policy. This makes rollbacks difficult and increases risk if unforeseen issues arise from the new behavior.

  getNextPageParam: GetNextPageParamFunction<TPageParam, TQueryFnData>
Commitable Suggestion
Suggested change
getNextPageParam?: GetNextPageParamFunction<TPageParam, TQueryFnData>
getNextPageParam: GetNextPageParamFunction<TPageParam, TQueryFnData>
Standards
  • Org-Guideline-Use feature flags for new functionality and include a clear rollback plan.

Comment on lines +91 to +94
const param =
fetchMore.pageParam === undefined
? pageParamFn(options, oldData)
: fetchMore.pageParam
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Definition and Runtime Behavior Mismatch

The runtime logic allows pageParam to override the result of getNextPageParam if both are provided. However, the accompanying type definitions explicitly forbid providing pageParam when getNextPageParam is defined. This discrepancy between the typed API contract and the actual runtime behavior can lead to confusion and unexpected behavior, undermining the reliability of the type system.

Standards
  • ISO-IEC-25010-Functional-Correctness-Appropriateness

Comment on lines +104 to +109
expectTypeOf<typeof observer.fetchNextPage>()
.parameter(0)
.toEqualTypeOf<
| { pageParam: number; cancelRefetch?: boolean; throwOnError?: boolean }
| undefined
>()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect Type Test Allows Undefined Arguments

The type test asserts that the options argument for fetchNextPage can be undefined, which contradicts the test's stated goal to 'require pageParam'. This lenient type allows calling fetchNextPage() without arguments when getNextPageParam is missing, which can lead to a silent runtime failure where the queryFn receives pageParam: undefined. The type should enforce that the options object containing pageParam is mandatory.

Standards
  • Type Safety & API Contracts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5990e and 644677e.

📒 Files selected for processing (6)
  • packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx (1 hunks)
  • packages/query-core/src/__tests__/infiniteQueryObserver.test-d.tsx (1 hunks)
  • packages/query-core/src/infiniteQueryBehavior.ts (4 hunks)
  • packages/query-core/src/infiniteQueryObserver.ts (1 hunks)
  • packages/query-core/src/query.ts (1 hunks)
  • packages/query-core/src/types.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/query-core/src/__tests__/infiniteQueryObserver.test-d.tsx (2)
packages/query-core/src/infiniteQueryObserver.ts (1)
  • InfiniteQueryObserver (27-198)
packages/query-core/src/__tests__/utils.ts (1)
  • queryKey (24-27)
packages/query-core/src/infiniteQueryObserver.ts (1)
packages/query-core/src/types.ts (2)
  • FetchNextPageOptions (586-596)
  • FetchPreviousPageOptions (598-608)
packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx (2)
packages/query-core/src/__tests__/utils.ts (1)
  • queryKey (24-27)
packages/query-core/src/infiniteQueryObserver.ts (1)
  • InfiniteQueryObserver (27-198)
🪛 GitHub Actions: pr
packages/query-core/src/infiniteQueryObserver.ts

[error] 122-122: TS2339: Property 'pageParam' does not exist on type 'FetchNextPageOptions'.

Comment on lines +85 to 97
const previous = fetchMore.direction === 'backward'
const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
const oldData = {
pages: oldPages,
pageParams: oldPageParams,
}
const param = pageParamFn(options, oldData)
const param =
fetchMore.pageParam === undefined
? pageParamFn(options, oldData)
: fetchMore.pageParam

result = await fetchPage(oldData, param, previous)
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Explicit pageParam is dropped on the very first fetch
If the consumer starts an infinite query with no cached pages (e.g. enabled: false) and then calls fetchNextPage({ pageParam }), fetchMore is populated but oldPages.length is 0. Because of the if (fetchMore && oldPages.length) guard we fall into the else branch, completely ignoring the caller-supplied pageParam and defaulting back to initialPageParam. That makes it impossible to bootstrap a query from a runtime-provided cursor—the main use case this feature is supposed to unlock.

Please let the fetchMore branch run even when there are no cached pages and treat an explicit pageParam override as the source of truth. Something like the diff below preserves the old behavior for existing pages while honoring manual cursors for the first fetch:

-        if (fetchMore && oldPages.length) {
-          const previous = fetchMore.direction === 'backward'
-          const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
-          const oldData = {
-            pages: oldPages,
-            pageParams: oldPageParams,
-          }
-          const param =
-            fetchMore.pageParam === undefined
-              ? pageParamFn(options, oldData)
-              : fetchMore.pageParam
-
-          result = await fetchPage(oldData, param, previous)
+        if (fetchMore) {
+          const previous = fetchMore.direction === 'backward'
+          const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
+          const baseData = oldPages.length
+            ? { pages: oldPages, pageParams: oldPageParams }
+            : { pages: [], pageParams: [] }
+          const param =
+            fetchMore.pageParam !== undefined
+              ? fetchMore.pageParam
+              : oldPages.length
+                ? pageParamFn(options, baseData)
+                : options.initialPageParam
+
+          result = await fetchPage(baseData, param, previous)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/query-core/src/infiniteQueryBehavior.ts around lines 85 to 97, the
current guard skips the fetchMore branch when there are no cached pages causing
an explicit fetchMore.pageParam to be ignored; change the condition so fetchMore
is processed even if oldPages.length === 0 when the caller provided a pageParam.
Specifically, always enter the fetchMore logic when fetchMore exists, compute
previous and pageParamFn as before, and derive param by preferring
fetchMore.pageParam when it is defined (use that value even if oldPages is
empty); only fall back to calling pageParamFn(options, oldData) when
fetchMore.pageParam is undefined (and for existing pages preserve current
behavior).

Comment on lines +127 to 136
fetchNextPage({ pageParam, ...options }: FetchNextPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'forward' },
fetchMore: { direction: 'forward', pageParam },
},
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Add pageParam to FetchNextPageOptions type definition.

The pipeline is failing because pageParam is being destructured from FetchNextPageOptions, but the type definition doesn't include this property. The relevant code snippets show that FetchNextPageOptions in types.ts (lines 585-595) only includes cancelRefetch.

To fix this, update the FetchNextPageOptions interface in packages/query-core/src/types.ts:

 export interface FetchNextPageOptions extends ResultOptions {
+  /**
+   * Optional page parameter to use when fetching the next page.
+   * If provided, this will override the value computed from getNextPageParam.
+   */
+  pageParam?: unknown
   /**
    * If set to `true`, calling `fetchNextPage` repeatedly will invoke `queryFn` every time,
    * whether the previous invocation has resolved or not. Also, the result from previous invocations will be ignored.
    *
    * If set to `false`, calling `fetchNextPage` repeatedly won't have any effect until the first invocation has resolved.
    *
    * Defaults to `true`.
    */
   cancelRefetch?: boolean
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/query-core/src/types.ts around lines 585 to 595, the
FetchNextPageOptions interface is missing the pageParam property but code in
infiniteQueryObserver.ts destructures pageParam from FetchNextPageOptions;
update the FetchNextPageOptions type to include an optional pageParam (e.g.
pageParam?: unknown or a properly generic page param type used across the
package), so the compiler knows this property exists and type-checks correctly.

Comment on lines +138 to 150
fetchPreviousPage({
pageParam,
...options
}: FetchPreviousPageOptions = {}): Promise<
InfiniteQueryObserverResult<TData, TError>
> {
return this.fetch({
...options,
meta: {
fetchMore: { direction: 'backward' },
fetchMore: { direction: 'backward', pageParam },
},
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Add pageParam to FetchPreviousPageOptions type definition.

The same issue applies here—pageParam is being destructured from FetchPreviousPageOptions, but the type definition doesn't include this property.

Update the FetchPreviousPageOptions interface in packages/query-core/src/types.ts:

 export interface FetchPreviousPageOptions extends ResultOptions {
+  /**
+   * Optional page parameter to use when fetching the previous page.
+   * If provided, this will override the value computed from getPreviousPageParam.
+   */
+  pageParam?: unknown
   /**
    * If set to `true`, calling `fetchPreviousPage` repeatedly will invoke `queryFn` every time,
    * whether the previous invocation has resolved or not. Also, the result from previous invocations will be ignored.
    *
    * If set to `false`, calling `fetchPreviousPage` repeatedly won't have any effect until the first invocation has resolved.
    *
    * Defaults to `true`.
    */
   cancelRefetch?: boolean
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/query-core/src/infiniteQueryObserver.ts around lines 138 to 150,
fetchPreviousPage destructures pageParam from FetchPreviousPageOptions but the
type definition lacks pageParam; update packages/query-core/src/types.ts to add
an optional pageParam?: unknown (or generic TPageParam) to the
FetchPreviousPageOptions interface (and any related
FetchNextPageOptions/FetchPageOptions types if present) so the destructured
property is correctly typed and preserves proper generics/optional usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants