winsoroaks
winsoroaks•15mo ago

configure ConvexReactClient to skip queries when input is undefined by default?

Hi team! Is it possible to enable "skip" when doing useQuery in the client? currently im adding a "isLoading" everywhere when i do useQuery.
const customer = useQuery(
api.customerFuncs.getCustomer,
isLoading
? "skip"
: {
id: customerId,
}
)
const customer = useQuery(
api.customerFuncs.getCustomer,
isLoading
? "skip"
: {
id: customerId,
}
)
i've checked the docs and dont see anything related. thanks!
9 Replies
Michal Srb
Michal Srb•15mo ago
Hey @winsoroaks, your code looks good! What's making customerId undefined? Are you fetching it from another query? For now we suggest grouping fetching into a single query where possible / ergonomical, which avoids the waterfall (waiting for customerId before fetching the customer). Alternatively to "skip" you could pass down undefined customerId to the server and handle it inside getCustomer, but this does incur an additional functional call (which might not be a problem in practice).
winsoroaks
winsoroaksOP•15mo ago
ok got it! thank you 🙂 that was an example. but most of the time, i think i've been relying on
const { orgRole, userId, isLoaded } = useAuth()
const { orgRole, userId, isLoaded } = useAuth()
userId from clerk to do a query
Aps
Aps•15mo ago
You could move authentication at a higher level in your app, so no other query is mounted until you are done with user authentication. If that's not possible you could use a helper hook like this:
function useIfAuthed<T>(params: T) {
const { isLoaded } = useAuth();
return isLoaded ? params : "skip";
}

function MyReactComponent() {
const customer = useQuery(
api.customerFuncs.getCustomer,
useIfAuthed({ id: customerId, })
)

// Do something with customer
}
function useIfAuthed<T>(params: T) {
const { isLoaded } = useAuth();
return isLoaded ? params : "skip";
}

function MyReactComponent() {
const customer = useQuery(
api.customerFuncs.getCustomer,
useIfAuthed({ id: customerId, })
)

// Do something with customer
}
Michal Srb
Michal Srb•15mo ago
Also if you follow our Auth integration, you should have access to the user ID via ctx.auth.getUserIdentity() without relying on passing it as an argument to a query (which might also not be secure depending on your setup)
winsoroaks
winsoroaksOP•15mo ago
great idea, thanks! cool, i'll give this a shot. i anecdotally ran into undefined a few times while the doc says, "getUserIdentity is guaranteed to have tokenIdentifier, subject and issuer fields." maybe i forgot to add a bang to the identity. will try and see how it goes. thanks, once again 🙂 tried it out, even adding a bang didnt quite work out.
[CONVEX Q(businessFuncs:getBusinessProfile)] [LOG] '🚀 ~ file: businessFuncs.ts:19 ~ handler: ~ identity:' null
logging.js:30 [CONVEX Q(businessFuncs:getBusinessProfile)] [LOG] '🚀 ~ file: businessFuncs.ts:20 ~ handler: ~ userId:' undefined
[CONVEX Q(businessFuncs:getBusinessProfile)] [LOG] '🚀 ~ file: businessFuncs.ts:19 ~ handler: ~ identity:' null
logging.js:30 [CONVEX Q(businessFuncs:getBusinessProfile)] [LOG] '🚀 ~ file: businessFuncs.ts:20 ~ handler: ~ userId:' undefined
export const getBusinessProfile = query({
handler: async (ctx) => {
const identity = await ctx.auth.getUserIdentity()
console.log(
"🚀 ~ file: businessFuncs.ts:19 ~ handler: ~ identity:",
identity
)
const userId = identity?.subject!
console.log("🚀 ~ file: businessFuncs.ts:20 ~ handler: ~ userId:", userId)
export const getBusinessProfile = query({
handler: async (ctx) => {
const identity = await ctx.auth.getUserIdentity()
console.log(
"🚀 ~ file: businessFuncs.ts:19 ~ handler: ~ identity:",
identity
)
const userId = identity?.subject!
console.log("🚀 ~ file: businessFuncs.ts:20 ~ handler: ~ userId:", userId)
doing the following works
const business = useQuery(
api.businessFuncs.getBusinessProfile,
isLoading ? "skip" : {}
)
const business = useQuery(
api.businessFuncs.getBusinessProfile,
isLoading ? "skip" : {}
)
Michal Srb
Michal Srb•15mo ago
Ah, so you do have a working auth setup, but you don't want to run the useQuery before the client is logged in. That makes sense, and you can avoid the "skip" if you only render the component when the client is authenticated: https://docs.convex.dev/auth/clerk#logged-in-and-logged-out-views
Convex Clerk | Convex Developer Hub
Clerk is an authentication platform providing login via
Aps
Aps•15mo ago
The only problem with this in hooks is that it's not reactive, so your component would not re-render when the authentication state changes.
Michal Srb
Michal Srb•15mo ago
@Aps everything should be reactive, what do you see is not updating for you?
Aps
Aps•15mo ago
I mean if you use directly ctx.auth.getUserIdentity() in your client side, you will not receive an event when identify is changed.

Did you find this page helpful?