hasanaktasTR
hasanaktasTR•5mo ago

Typescript error for @tanstack/react-query when extra parameter is added

lookup.ts (convex. server)
import { zCustomQuery } from "convex-helpers/server/zod";
import { query } from "./_generated/server";
import { NoOp } from "convex-helpers/server/customFunctions";


const publicQuery = zCustomQuery(query, NoOp);

export const getCountries = publicQuery({
handler: async (ctx) => {
const countries = await ctx.db.query("countries").collect();

return countries;
},
});
import { zCustomQuery } from "convex-helpers/server/zod";
import { query } from "./_generated/server";
import { NoOp } from "convex-helpers/server/customFunctions";


const publicQuery = zCustomQuery(query, NoOp);

export const getCountries = publicQuery({
handler: async (ctx) => {
const countries = await ctx.db.query("countries").collect();

return countries;
},
});
client.ts
import { convexQuery } from "@convex-dev/react-query";
import { useQuery } from "@tanstack/react-query";
import { api } from "@server/backend/convex/_generated/api";



const Component = () => {
const countries1Query = useQuery(convexQuery(api.lookup.getCountries, { }));

const countries2Query = useQuery({
...convexQuery(api.lookup.getCountries, { })
});

const countries3Query = useQuery({
...convexQuery(api.lookup.getCountries, { }),
initialData:[]
});

return null

}
import { convexQuery } from "@convex-dev/react-query";
import { useQuery } from "@tanstack/react-query";
import { api } from "@server/backend/convex/_generated/api";



const Component = () => {
const countries1Query = useQuery(convexQuery(api.lookup.getCountries, { }));

const countries2Query = useQuery({
...convexQuery(api.lookup.getCountries, { })
});

const countries3Query = useQuery({
...convexQuery(api.lookup.getCountries, { }),
initialData:[]
});

return null

}
countries 3 query gives error
13 Replies
ballingt
ballingt•5mo ago
what a monster error I'm looking into it
hasanaktasTR
hasanaktasTROP•5mo ago
If we give initialData as below, it works. As far as I can see, convexQuery does not return a queryFn. Normally, tanstack-query automatically infers the type of initialData from there. I couldn't find a quick solution. It would be useful for the library author to look into this. If it is going to be used this way, it would be useful to add it to the documentation.
const countries3Query = useQuery({
...convexQuery(api.lookup.getCountries, { }),
initialData:[] as FunctionReturnType<typeof api.lookup.getCountries>
});
const countries3Query = useQuery({
...convexQuery(api.lookup.getCountries, { }),
initialData:[] as FunctionReturnType<typeof api.lookup.getCountries>
});
ballingt
ballingt•5mo ago
[edit: the other impl of] convexQuery does return a queryFn https://github.com/get-convex/convex-react-query/blob/13698dde5f0ba04bf812b3407da84ffa99f07ec1/src/index.ts#L358 but there's clearly something wrong here, let me see if I can repro Oh you're right @hasanaktasTR! It's specified globally
hasanaktasTR
hasanaktasTROP•5mo ago
due to the nature of convex, most things are not used on the tanstack-query side anyway. (refetch, retry, stale, etc...) I wonder if the tanstack-query parameters we can give should be taken as a parameter in the convexQuery function? In this way, type safety for things like initialData etc. will be ensured.
ballingt
ballingt•5mo ago
thanks @hasanaktasTR , I filed this https://github.com/get-convex/convex-react-query/issues/2 and am looking into it. That's a good idea, better than the previous way I tried this with
const asdf = useConvexQuery({})
const asdf = useConvexQuery({})
where we had to wrap all the types I'd like to make this way work if we can, the simplicity of query options you can spread more options into is nice but as you point out it'd be great to filter to the relevant properties Convex actions work a lot more like traditional fetch endpoints,
useQuery(convexAction(api.messages.slowNonReactiveEndpoint, {}))
useQuery(convexAction(api.messages.slowNonReactiveEndpoint, {}))
so I'd like that one to work this way at least
ballingt
ballingt•5mo ago
@hasanaktasTR this was a later change, I had things working when it was a method, which indeed included returning the queryFn instead of setting it globally.
No description
hasanaktasTR
hasanaktasTROP•5mo ago
I didn't know it was used this way. As you said, with a correction on the TypeScript side, it seems like the current flow can continue. I will follow the developments. Good luck. @ballingt Also, my personal suggestion is that in the company I work for, we generally use react-query in our projects for connection to the API. Although convex is a complete solution in most project scenarios, react-query can be used for connection to external APIs. For this reason, instead of giving queryKeyHashFn and queryFn globally, it seems cleaner to me to continue this flow with a custom hook (for example useConvexTanstackQuery) that we can use generally, as you said.
ballingt
ballingt•5mo ago
I've got a fix in, thanks for reporting! I'll let you know when it's out. That makes sense, I'll at least mention both approaches in the docs. The global configuration was intially necessary because a custom query key hash function can only be set globally, and some particular convex keys cannot be hashed with the default queryKeyHashFn. But changes have made that less necessary, now it's only for convenience. Now convexQuery() transforms the api.foo.bar into something serializeable and could do the same for the args {} Oh the other reason it's nice to set the queryFn globally is that then you don't have to have a reference to the convexQueryCache. So that will probably be the tradeoff, either use
// set queryFn globally, and use
const q = useQuery(convexQuery(api.foo.bar, {}))

// don't set queryFn globally, and use
const q = useQuery(convexQueryCache.queryOptions(api.foo.bar, {}))
// set queryFn globally, and use
const q = useQuery(convexQuery(api.foo.bar, {}))

// don't set queryFn globally, and use
const q = useQuery(convexQueryCache.queryOptions(api.foo.bar, {}))
Thanks for your input here, would love to hear how using this goes. We really like TanStack Query at Convex and are interested in making this as simple as possible.
hasanaktasTR
hasanaktasTROP•5mo ago
For the second scenario, I can use it as follows, so do I understand correctly?
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { ConvexQueryClient } from "@convex-dev/react-query";
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
import { api } from "@uniobb/backend/convex/_generated/api";
import { ConvexReactClient } from "convex/react";
import { FunctionArgs, FunctionReference } from "convex/server";

export const convex = new ConvexReactClient("");
export const convexQueryClient = new ConvexQueryClient(convex);

const queryClient = new QueryClient({});

convexQueryClient.connect(queryClient);

export const Provider = ({ children }: { children: React.ReactNode }) => {
return (
<ConvexAuthProvider client={convex}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</ConvexAuthProvider>
);
};




export const useConvexTanstackQuery=<ConvexQueryReference extends FunctionReference<"query">>(
funcRef: ConvexQueryReference,
queryArgs: FunctionArgs<ConvexQueryReference>,
)=>{
return useQuery(convexQueryClient.queryOptions(funcRef,queryArgs))
}



// Example

useConvexTanstackQuery(api.account.getProfile,{})
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { ConvexQueryClient } from "@convex-dev/react-query";
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
import { api } from "@uniobb/backend/convex/_generated/api";
import { ConvexReactClient } from "convex/react";
import { FunctionArgs, FunctionReference } from "convex/server";

export const convex = new ConvexReactClient("");
export const convexQueryClient = new ConvexQueryClient(convex);

const queryClient = new QueryClient({});

convexQueryClient.connect(queryClient);

export const Provider = ({ children }: { children: React.ReactNode }) => {
return (
<ConvexAuthProvider client={convex}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</ConvexAuthProvider>
);
};




export const useConvexTanstackQuery=<ConvexQueryReference extends FunctionReference<"query">>(
funcRef: ConvexQueryReference,
queryArgs: FunctionArgs<ConvexQueryReference>,
)=>{
return useQuery(convexQueryClient.queryOptions(funcRef,queryArgs))
}



// Example

useConvexTanstackQuery(api.account.getProfile,{})
ballingt
ballingt•5mo ago
You should be able to just use
const q = useQuery(convexQueryCache.queryOptions(api.foo.bar, {}))
const q = useQuery(convexQueryCache.queryOptions(api.foo.bar, {}))
which you could wrap in your own hook like useConvexTanStackQuery if you'd like, but you don't need to
hasanaktasTR
hasanaktasTROP•5mo ago
You're right Tom. I'm not going to write a custom hook and mess with type safety 🙂
ballingt
ballingt•5mo ago
@hasanaktasTR I just released @convex-dev/react-query@0.0.0-alpha.4, you can npm install that to get the behavior you reported fixed I'll look into some of the rest of this
hasanaktasTR
hasanaktasTROP•5mo ago
error fixed @ballingt thanks

Did you find this page helpful?