#Unable to fetch data in my table using the useQuery

12 messages · Page 1 of 1 (latest)

wary cedar
#

Now my nextjs app is crushing whenever I go to that page of budgets

thorn tulip
#

Hmm I'd rather not download this pdf from an unknown source, can you type out the information?

#

Or just convert to an image

thorn tulip
#

I've deleted the original message, which was just a file, as it's a security risk. Happy to help if you offer more info, though!

wary cedar
#

Okay sure let me share screenshots

#

component : budget-card.tsx

"use client";

import { useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";
import BudgetCard from "@/components/budget-card";

export default function BudgetPage() {
const currentUser = useQuery(api.users.current);
const budgets = useQuery(
api.budget.getBudgetsByUser,
currentUser ? { userId: currentUser._id } : "skip"
);

if (!currentUser) return <p>Loading user...</p>;
if (!budgets) return <p>Loading budgets...</p>;

if (!budgets) return <p>No budgets available.</p>;

return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{budgets.map((budget) => (
<BudgetCard
key={budget._id}
title={budget.categoryId}
budgetLimit={budget.limit}
currentSpending={budget.spent}
remainingAmount={budget.remaining}
progress={((budget.spent / budget.limit) * 100).toFixed(1)}
currency="RWF"
/>
))}
</div>
);
}

#

Function : budget.ts
import { mutation, query } from "./_generated/server";
import { v } from "convex/values";

export const create = mutation({
args: {
categoryId: v.string(),
limit: v.float64(),
remaining: v.float64(),
spent: v.float64(),
date: v.string(),
userId: v.id("users"),
},
handler: async (ctx, args) => {
return await ctx.db.insert("budgets", args);
},
});

// getting the budget by user id
export const getBudgetsByUser = query({
args: { userId: v.id("users") },
handler: async (ctx, args) => {
return await ctx.db
.query("budgets")
.withIndex("byUserId", (q) => q.eq("userId", args.userId))
.collect();
},
});

#

SCHEMA.TS:
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
users: defineTable({
email: v.string(),
clerkUserId: v.string(),
firstName: v.optional(v.string()),
lastName: v.optional(v.string()),
imageUrl: v.optional(v.string()),
}).index("byClerkUserId", ["clerkUserId"]),

accounts: defineTable({
userId: v.id("users"),
name: v.string(),
type: v.string(),
balance: v.float64(),
}).index("byUserId", ["userId"]),

transactions: defineTable({
userId: v.id("users"),
accountId: v.id("accounts"),
type: v.union(v.literal("income"), v.literal("expense")),
amount: v.float64(),
description: v.optional(v.string()),
categoryId: v.optional(v.id("categories")),
})
.index("byUserId", ["userId"])
.index("byAccountId", ["accountId"]),

budgets: defineTable({
categoryId: v.string(),
limit: v.float64(),
remaining: v.float64(),
spent: v.float64(),
date: v.string(),
userId: v.id("users"),
})
.index("byCategoryId", ["categoryId"])
.index("byUserId", ["userId"]),

categories: defineTable({
userId: v.id("users"),
name: v.string(),
parentCategoryId: v.optional(v.id("categories")), // For subcategories
}).index("byUserId", ["userId"]),

notifications: defineTable({
userId: v.id("users"),
message: v.string(),
type: v.union(v.literal("budget"), v.literal("transaction")),
read: v.boolean(),
}).index("byUserId", ["userId"]),
});

thorn tulip
#

Got it - can you share the error(s) you're seeing?

worthy void
#
export default function BudgetPage() {
  const currentUser = useQuery(api.users.current);
  const budgets = useQuery(
    api.budget.getBudgetsByUser,
    currentUser ? { userId: currentUser._id } : "skip"
  );

The budget query depends on the value of currentUser, which may still not be available when the query is executed.
When currentUser is not defined you are passing "skip" as an argument to your query, but your wuery wants an {userId: v.id("users"}} object

The most basic strategy in react to create a dependence is to have a wrapper component where you execute the user query, and render the budget component only when currentUser is defined.

However I would advise you to make use of the Authenticated components found in import { Authenticated, Unauthenticated } from "convex/react";

and then use a either Context or the const userId = await getAuthUserId(ctx); functionality found in import { getAuthUserId } from "@convex-dev/auth/server";

you are also checking twice if budgets is falsy, I assume your second check should be done on budgets.length

  if (!budgets) return <p>Loading budgets...</p>;

  if (!budgets) return <p>No budgets available.</p>;
thorn tulip
#

They're doing it right, "skip" is a part of the useQuery api, it's how you avoid the hook running before auth.