useSuspenseQuery always called on initial render

Using - t3stack, - trpc 11 - nextAuth 4 The code - I have a protected procedure habit.getByUser - I call useSession and wait for my user session - Once I have the session I render the suspenseful component - Inside the suspenseful component I call my procedure with useSuspenseQuery The problem - This produces a TRPCError: UNAUTHORIZED error on initial render - But it subsequently re-renders once it gets the user session and the procedure executes perfectly Notes - I've tried multiple different ways of preventing the component from rendering immediately but it seems like useSuspenseQuery is always called - I can fix this issue by replacing useSuspenseQuery with a normal useQuery. I just don't know why that works.
"use client";

import { api } from "~/trpc/react";
import { Card } from "~/components/ui/card";
import AddHabitDialog from "./add-habit-dialog";
import EditHabitForm from "./edit-habit-form";
import ListSkeleton from "./skeletons/list-skeleton";
import { Fragment, Suspense } from "react";
import { useSession } from "next-auth/react";

export function MyHabits() {
const [myHabits] = api.habit.getByUser.useSuspenseQuery();

return myHabits ? (
myHabits.map((habit) => (
<Fragment key={habit.id}>
<EditHabitForm habit={habit} />
<hr />
</Fragment>
))
) : (
<p>You have no habits yet.</p>
);
}

export function MyHabitsContainer() {
const { data: session } = useSession();

return (
<Card className="flex flex-col gap-4 p-4">
{session?.user && (
<Suspense fallback={<ListSkeleton />}>
<span>My habits</span>
<MyHabits />
</Suspense>
)}
<AddHabitDialog />
</Card>
);
}
"use client";

import { api } from "~/trpc/react";
import { Card } from "~/components/ui/card";
import AddHabitDialog from "./add-habit-dialog";
import EditHabitForm from "./edit-habit-form";
import ListSkeleton from "./skeletons/list-skeleton";
import { Fragment, Suspense } from "react";
import { useSession } from "next-auth/react";

export function MyHabits() {
const [myHabits] = api.habit.getByUser.useSuspenseQuery();

return myHabits ? (
myHabits.map((habit) => (
<Fragment key={habit.id}>
<EditHabitForm habit={habit} />
<hr />
</Fragment>
))
) : (
<p>You have no habits yet.</p>
);
}

export function MyHabitsContainer() {
const { data: session } = useSession();

return (
<Card className="flex flex-col gap-4 p-4">
{session?.user && (
<Suspense fallback={<ListSkeleton />}>
<span>My habits</span>
<MyHabits />
</Suspense>
)}
<AddHabitDialog />
</Card>
);
}
7 Replies
Sean
Sean4w ago
In order to useSuspenseQuery to be called, the suspense above the component needs to be rendered. Have you tried debugging of what is the value of session?.user? In my opinion there is a value that is different from null or undefined to session.user and therefore the suspense component is being rendered while the user still not authorized and therefore causes you the error you're experiening
conlonj25
conlonj25OP4w ago
So, if I console.log the user data in each function: - My React Component (MyHabitsContainer) console.log("CLIENT SIDE", session?.user); - My TRPC procedure (getByUser) console.log("SERVER SIDE", ctx.session.user); - TRPC protectedProcedure (src/server/api/trpc.ts) console.log('PROTECTED PROCEDURE', ctx.session?.user); I get the following logs for a single page render. In this order.
CLIENT SIDE `some user data`
PROTECTED PROCEDURE undefined
PROTECTED PROCEDURE `some user data`
SERVER SIDE `some user data`
CLIENT SIDE `some user data`
PROTECTED PROCEDURE undefined
PROTECTED PROCEDURE `some user data`
SERVER SIDE `some user data`
Sean
Sean4w ago
Yeah as I said, since you’ve got that inside session.user then the suspense renders and then the query triggers Idk the api syntax since I havent used trpc but you should dig dipper with the user session and look when the user is authorized and when hes not and when the components are being rendered
conlonj25
conlonj25OP4w ago
Sorry, some user data is just a placeholder for a legit user object. I didn't wanna dox myself. So that first console.log actually returns my logged-in user object I assume once I have a proper user object I have a green light to go ahead and execute any protected procedures?
Sean
Sean4w ago
Yeah I assume that too
conlonj25
conlonj25OP4w ago
Ok, not the safest assumption I guess. It's just weird. It seems like a perfectly legit use of everything. Anyway, I have another fix I can use. Cheers for taking a look!
Sean
Sean4w ago
You welcome 🙂

Did you find this page helpful?