Web Dev Cody
Web Dev Cody14mo ago

Trying to get a loader working correctly

I'm trying to setup logic in my front end to show skeleton loaders when a page is loading on a query, but I'm not sure the best practice right now my query looks like this
export const getUserPlans = query({
handler: async (ctx) => {
const userId = await getUserId(ctx);

if (!userId) {
return {
error: 'no user id was found',
};
}

return await ctx.db
.query('plans')
.withIndex('by_userId', (q) => q.eq('userId', userId))
.collect();
})
export const getUserPlans = query({
handler: async (ctx) => {
const userId = await getUserId(ctx);

if (!userId) {
return {
error: 'no user id was found',
};
}

return await ctx.db
.query('plans')
.withIndex('by_userId', (q) => q.eq('userId', userId))
.collect();
})
and in the front end I do something like this
const plans = useQuery(api.plans.queries.getUserPlans);

if (isError(plans) || plans === undefined) {
return <Loader />
}
const plans = useQuery(api.plans.queries.getUserPlans);

if (isError(plans) || plans === undefined) {
return <Loader />
}
but I'm seeing some behavior where the convex endpoint is invoked before the user is actually authenticated, so it returns the error. I'm wondering if there is a better way to setup the front end to never invoke my convex backend until my auth is all 100% setup
8 Replies
jamwt
jamwt14mo ago
yeah, if you rely solely on the webhook to populate the user record, then there is a potential race. which is why many apps have the app create the user record if it wins the race (using the credentials in getUserIdentity). you could also just return null or something b/c after the webhook fires, the query will re-render with the appropriate user
Web Dev Cody
Web Dev CodyOP14mo ago
I may have explained my question poorly. So this is when I already have an authenticated user in my convex db and also in clerk. I load a page which runs a query to get an array of data, but I’m seeing it return the following data. Undefined, then it returns [], then it returns all of the records. So my ui switches between a loading state, to a “no data found” state, and then to a list all data state The reason is because the ui seems to run the query before it’s fully setup with auth, which causes the backend to return its [] because no user id was set I think I tried also using the useConvexSession, but maybe I did it wrong. Now that I think about it, I probably should never be rendering the component that runs the query until I verify isLoggedIn is set Or I forget if the useQuery provides a {enabled: isLoggedIn} option yet
jamwt
jamwt14mo ago
ah, yes. that variation of it is the "skipped' one
jamwt
jamwt14mo ago
Convex React | Convex Developer Hub
Convex React is the client library enabling your React application to interact
jamwt
jamwt14mo ago
use that with isAuthenticated -- do I have it right now? that will wait to run the fetch until the clerk auth is done in the app without conditional hook rule violations or whatever
Michal Srb
Michal Srb14mo ago
@Web Dev Cody I return null (if there is no viewer, if the viewer doesn't have permission, etc.) and then do
if (result == null) {
return <Skeleton />
}
return ...
if (result == null) {
return <Skeleton />
}
return ...
You can see this here: https://github.com/xixixao/saas-starter/blob/main/app/t/TeamSwitcher.tsx#L46 server side example: https://github.com/xixixao/saas-starter/blob/main/convex/users/teams/members.ts#L34-L40 The reason I don't throw is because if the data got just deleted, I don't want the frontend to throw (instead I have a hook that changes what is shown or redirects the user). But you could totally return {error: "foo"} on the backend (or anything else), and be explicit on the client (result === undefined || result === null || 'error' in result))
GitHub
saas-starter/convex/users/teams/members.ts at main · xixixao/saas-s...
Convex, Clerk, Next.js, Convex Ents. Contribute to xixixao/saas-starter development by creating an account on GitHub.
GitHub
saas-starter/app/t/TeamSwitcher.tsx at main · xixixao/saas-starter
Convex, Clerk, Next.js, Convex Ents. Contribute to xixixao/saas-starter development by creating an account on GitHub.
Michal Srb
Michal Srb14mo ago
And if you actually need "null or something" as a return value (where null is a valid loaded value), you can still use this pattern and return from the query {value: null} or {value: something}
Web Dev Cody
Web Dev CodyOP14mo ago
thanks I'l check these out

Did you find this page helpful?