#Paginated queries sometimes dont load the first page

5 messages · Page 1 of 1 (latest)

twilit mason
#

I have an issue where I am trying to load a paginated query. It is inconsistent with loading, sometimes it works fine but a bunch of times it will be stuck on "LoadingFirstPage" status.

The query is pretty basic,

import { DataModel } from "convexDataModel";
import { GenericQueryCtx, paginationOptsValidator } from "convex/server";
import { Infer, v } from "convex/values";
import { Channel } from "@convex/channels/channels.schema";

export const readChannelsPaginatedValidator = v.object({
mode: v.optional(Channel.fields.mode),
paginationOpts: paginationOptsValidator,
});

export const readChannelsPaginated = async (
ctx: GenericQueryCtx<DataModel>,
args: Infer<typeof readChannelsPaginatedValidator>,
) =>
ctx.db
.query("channels")
.withIndex("by_setupStage_visibility_mode", (q) =>
q
.eq("setupStage", "complete")
.eq("visibility", "public")
.eq("mode", args.mode ?? "schedule"),
)
.order("desc")
.paginate(args.paginationOpts);

I looked at the convex logs and I even noticed that it doesn't show the query hitting the backend, like it never even queried.

Here is the usePaginatedQuery logic:

import { usePaginatedQuery } from "convex/react";

import { api } from "convexApi";

export const CHANNEL_PAGINATION_SIZE = 15;

export const useGetChannelsPaginatedQuery = (args: {
mode?: "schedule" | "watchparty";
}) =>
usePaginatedQuery(
api.channels.queries.getChannelsPaginated,
{
mode: args.mode,
},
{
initialNumItems: CHANNEL_PAGINATION_SIZE,
},
);

celest fieldBOT
#

Hi @twilit mason. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Your issue—where a paginated query sometimes gets stuck on the "LoadingFirstPage" status and doesn't even hit the backend—can be caused by a few things, based on Convex documentation and community discussions.

Possible Causes

  1. Arguments or Query Reference Changing

    • If the arguments or the query reference passed to usePaginatedQuery change between renders, the pagination state will reset to the first page. This can cause the hook to re-enter the "LoadingFirstPage" state and potentially never proceed if the arguments are unstable or undefined at first render. Make sure the args object is stable and not being recreated or changed unexpectedly between renders. For example, avoid creating new objects inline or using values that might be undefined on the first render and then set later (e.g., from async data or context) see docs.
  2. "skip" Argument

    • If you pass "skip" as the arguments to usePaginatedQuery, it will not make a backend request and will return undefined. Double-check that your arguments are not conditionally set to "skip" or undefined see docs.
  3. Component Mounting/Unmounting

    • If your component is mounting and unmounting rapidly (for example, due to parent state changes), the subscription may be canceled before the query is sent. Ensure your component tree is stable.
  4. Network or Auth Issues

    • If there are authentication issues or network problems, the query may not be sent. However, you mentioned nothing appears in the logs, which suggests the issue is on the client side before the request is made.

Debugging Steps

#
  • Log the Arguments: Add a console.log for the arguments passed to usePaginatedQuery to ensure they are always defined and stable.
  • Check for Conditional Rendering: Make sure the hook is not being called conditionally or after an early return, which is not allowed in React.
  • Stable Object References: Use useMemo or define the arguments object outside the component if possible, to avoid unnecessary re-renders and resets.

Example of Correct Usage

import { usePaginatedQuery } from "convex/react";
import { api } from "convexApi";

export const CHANNEL_PAGINATION_SIZE = 15;

export const useGetChannelsPaginatedQuery = (args: { mode?: "schedule" | "watchparty" }) => {
  // Ensure args is stable
  const stableArgs = React.useMemo(() => ({ mode: args.mode }), [args.mode]);
  return usePaginatedQuery(
    api.channels.queries.getChannelsPaginated,
    stableArgs,
    { initialNumItems: CHANNEL_PAGINATION_SIZE }
  );
};

This ensures the arguments object is stable and doesn't cause unnecessary resets.

Additional Notes

  • The usePaginatedQuery hook is designed to be fully reactive and should always trigger a backend request unless intentionally skipped or misconfigured see docs.
  • If you continue to see this issue and have ruled out argument instability, consider checking for any global state or context that might be affecting the component's lifecycle.

If after these checks the issue persists, it may be a bug or an edge case not covered in the documentation, and you should consider opening an issue with a minimal reproduction.