korz
korz•2mo ago

pagination and TanStack Start

In https://docs.convex.dev/client/react/tanstack-start
Using Convex React hooks Convex React hooks like usePaginatedQuery can be used alongside TanStack hooks. These hooks reference the same Convex Client so there's still just one set of consistent query results in your app when these are combined.
Is the code below the correct use of the usePaginatedQuery hook with TanStack Start?
import { convexQuery } from "@convex-dev/react-query";
import { useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { api } from "../../convex/_generated/api";
import { usePaginatedQuery } from "convex/react";

export const Route = createFileRoute("/")({
component: Home,
loader: async ({ context }) => {
await context.queryClient.ensureQueryData(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
);
},
});

function Home() {
const {
results: fontsPaginated,
status,
loadMore,
} = usePaginatedQuery(
api.fonts.listFontsPaginated,
{},
{ initialNumItems: 12 },
);

const { data: firstPageFonts } = useSuspenseQuery(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
);

const firstPageLoaded =
status !== "LoadingFirstPage" && fontsPaginated.length >= 12;

const fonts = firstPageLoaded ? fontsPaginated : firstPageFonts.page;

return <div>{fonts.map((f) => f.family)}</div>;
}
import { convexQuery } from "@convex-dev/react-query";
import { useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { api } from "../../convex/_generated/api";
import { usePaginatedQuery } from "convex/react";

export const Route = createFileRoute("/")({
component: Home,
loader: async ({ context }) => {
await context.queryClient.ensureQueryData(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
);
},
});

function Home() {
const {
results: fontsPaginated,
status,
loadMore,
} = usePaginatedQuery(
api.fonts.listFontsPaginated,
{},
{ initialNumItems: 12 },
);

const { data: firstPageFonts } = useSuspenseQuery(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
);

const firstPageLoaded =
status !== "LoadingFirstPage" && fontsPaginated.length >= 12;

const fonts = firstPageLoaded ? fontsPaginated : firstPageFonts.page;

return <div>{fonts.map((f) => f.family)}</div>;
}
TanStack Start | Convex Developer Hub
TanStack Start is a new React web framework
38 Replies
Convex Bot
Convex Bot•2mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
korz
korzOP•2mo ago
The goal is to have an infinite scroll page with the initial data is rendered by the server. The useSuspenseQuery resolves, but the usePaginatedQuery remains in a pending state. It looks like the query is never invoked when isolated after having a look at the server logs.
export const listFontsPaginated = query({
args: { paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const results = await ctx.db
.query("fonts")
.order("desc")
.paginate(args.paginationOpts);

console.log({ results });

return results;
},
});
export const listFontsPaginated = query({
args: { paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const results = await ctx.db
.query("fonts")
.order("desc")
.paginate(args.paginationOpts);

console.log({ results });

return results;
},
});
also TanStack Start is in Beta now 🎊
ballingt
ballingt•2mo ago
there's no supported way to use usePaginatedQuery with useSuspenseQuery yet this looks like a good direction but there's work in the library to be done to do this
korz
korzOP•2mo ago
the thing is when I strip out the suspense and loader code, the usePaginatedQuery problem still persists.
ballingt
ballingt•2mo ago
I hope a straight usePaginatedQuery() works, are you saying that's not working too?
korz
korzOP•2mo ago
correct.
ballingt
ballingt•2mo ago
Could you show that code?
korz
korzOP•2mo ago
export const Route = createFileRoute("/")({
component: Home,
// loader: async ({ context }) => {
// await context.queryClient.ensureQueryData(
// convexQuery(api.fonts.listFontsPaginated, {
// paginationOpts: {
// cursor: null,
// numItems: 12,
// },
// }),
// );
// },
});

function Home() {
const {
results: fontsPaginated,
status,
loadMore,
...rest
} = usePaginatedQuery(
api.fonts.listFontsPaginated,
{},
{ initialNumItems: 12 },
);

// const { data: firstPageFonts } = useSuspenseQuery(
// convexQuery(api.fonts.listFontsPaginated, {
// paginationOpts: {
// cursor: null,
// numItems: 12,
// },
// }),
// );

const firstPageLoaded =
status !== "LoadingFirstPage" && fontsPaginated.length >= 12;

// const fonts = firstPageLoaded ? fontsPaginated : firstPageFonts.page;

console.log({ fontsPaginated, status, rest }, fontsPaginated.length);

// useEffect(() => {
// console.log("loadMore");

// loadMore(12);
// });

return (
<div>
{fontsPaginated.map((f) => {
console.log({ family: f.family });

return f.family;
})}
</div>
);
}
export const Route = createFileRoute("/")({
component: Home,
// loader: async ({ context }) => {
// await context.queryClient.ensureQueryData(
// convexQuery(api.fonts.listFontsPaginated, {
// paginationOpts: {
// cursor: null,
// numItems: 12,
// },
// }),
// );
// },
});

function Home() {
const {
results: fontsPaginated,
status,
loadMore,
...rest
} = usePaginatedQuery(
api.fonts.listFontsPaginated,
{},
{ initialNumItems: 12 },
);

// const { data: firstPageFonts } = useSuspenseQuery(
// convexQuery(api.fonts.listFontsPaginated, {
// paginationOpts: {
// cursor: null,
// numItems: 12,
// },
// }),
// );

const firstPageLoaded =
status !== "LoadingFirstPage" && fontsPaginated.length >= 12;

// const fonts = firstPageLoaded ? fontsPaginated : firstPageFonts.page;

console.log({ fontsPaginated, status, rest }, fontsPaginated.length);

// useEffect(() => {
// console.log("loadMore");

// loadMore(12);
// });

return (
<div>
{fontsPaginated.map((f) => {
console.log({ family: f.family });

return f.family;
})}
</div>
);
}
ballingt
ballingt•2mo ago
so fontsPaginated is always undefined?
korz
korzOP•2mo ago
yes
{
fontsPaginated: [],
status: 'LoadingFirstPage',
rest: { isLoading: true, loadMore: [Function: loadMore] }
} 0
{
fontsPaginated: [],
status: 'LoadingFirstPage',
rest: { isLoading: true, loadMore: [Function: loadMore] }
} 0
ballingt
ballingt•2mo ago
ah
korz
korzOP•2mo ago
and the query is never invoked i see no logs from the console.log in the query def
ballingt
ballingt•2mo ago
oh try useConvexPaginatedQuery just in case you're using usePaginatedQuery imported from react-query or make sure that usePaginatedQuery is imported from "convex/react"
korz
korzOP•2mo ago
import { useConvexPaginatedQuery } from "@convex-dev/react-query"; import { usePaginatedQuery } from "convex/react"; yea neither work
ballingt
ballingt•2mo ago
and sounds like the function isn't running based on convex backend logs could you check the websocket, see if there's a query with that name being requested? do other normal Convex hooks work? like useQuery from "convex/react", or useConvexQuery from "@convex-dev/react-query"?
korz
korzOP•2mo ago
No description
korz
korzOP•2mo ago
const data = useQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
});
const data = useQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
});
data is undefined from convex/react same for useConvexQuery
ballingt
ballingt•2mo ago
it's expected these are undefined at first, but you're saying they stay undefined forever?
korz
korzOP•2mo ago
however this code works as expected
const { data: firstPageFonts } = useSuspenseQuery(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
const { data: firstPageFonts } = useSuspenseQuery(
convexQuery(api.fonts.listFontsPaginated, {
paginationOpts: {
cursor: null,
numItems: 12,
},
}),
ballingt
ballingt•2mo ago
So is sounds like nothing works form the client at all useSuspenseQuery runs on the server for SSR (as well as on the client) That might be the wrong websocket
korz
korzOP•2mo ago
nothing gets rendered
ballingt
ballingt•2mo ago
the websocket connection we're looking for hits an endpoint called /sync maybe there is no websocket If you put a console.log("hello") next to the COnvexProvider, does that run on the client? do you have a <ConvexProvider> component somewhere? Or if you put a console.log next to this useQuery, does that run on the lcient? You say TanStack Start so I'd think everything would run on the client
korz
korzOP•2mo ago
i see console logs from vinxi and the client
ballingt
ballingt•2mo ago
Could you shre this? is there an example you based this on?
korz
korzOP•2mo ago
i used npm create convex@latest -- -t tanstack-start ill share the repo. just gotta create some seed data
ballingt
ballingt•2mo ago
once I add the seed data I get something, with or without suspense
No description
ballingt
ballingt•2mo ago
I think that's the only change i made, in app/routes/index.tsx
ballingt
ballingt•2mo ago
No description
ballingt
ballingt•2mo ago
this is the websocket I mean
No description
korz
korzOP•2mo ago
ive done no work on the frontend so im just gonna start fresh as a sanity check and if the problem persists ill share the repo i am getting some client errors client.tsx:10 Uncaught Error: Root element not found at client.tsx:10:9 site.webmanifest:1 Manifest: Line: 1, column: 1, Syntax error. so something aint right
ballingt
ballingt•2mo ago
Oh what versions o fthings are youusing there are changes I need to make, in the beta Root doesn't exist anymore here let me do that right now, that ight be the confusino
korz
korzOP•2mo ago
"convex": "^1.17.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@convex-dev/react-query": "^0.0.0-alpha.8",

"@tanstack/react-query": "^5.60.2",
"@tanstack/react-query-devtools": "^5.61.0",
"@tanstack/react-router": "^1.77.5",
"@tanstack/react-router-with-query": "^1.77.5",
"@tanstack/react-virtual": "^3.10.9",
"@tanstack/router-devtools": "^1.82.2",
"@tanstack/start": "^1.77.5",
"convex": "^1.17.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@convex-dev/react-query": "^0.0.0-alpha.8",

"@tanstack/react-query": "^5.60.2",
"@tanstack/react-query-devtools": "^5.61.0",
"@tanstack/react-router": "^1.77.5",
"@tanstack/react-router-with-query": "^1.77.5",
"@tanstack/react-virtual": "^3.10.9",
"@tanstack/router-devtools": "^1.82.2",
"@tanstack/start": "^1.77.5",
ballingt
ballingt•2mo ago
well what versions are you using though those ^ mean it could be anything here's I'll fix these
korz
korzOP•2mo ago
oh yea lol
ballingt
ballingt•2mo ago
ok sorry about that! I hadn't updated the template since the last change before the beta
ballingt
ballingt•2mo ago
gotta update the quickstart too
korz
korzOP•2mo ago
thanks Tom! We're in business.

Did you find this page helpful?