Loading UI not showing

hey folks I'm using the T3 stack with app router I'm fetching some data and on the basis of data I'm generating the component I have wrapped that in a Suspense and I provided a fallback also but until the components aren't ready the loading UI doesn't shows up the page loads with full content here is my code
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { getServerAuthSession } from "@/server/auth";
import { api } from "@/trpc/server";
import { Container, Grid, Heading } from "@radix-ui/themes";
import GuildCard, { LoadingGuildCard } from "@/app/_components/GuildCard";

export default async function Page() {
const session = await getServerAuthSession();
if (!session || !session.user) {
redirect("/");
}
const discord = await api.discord.getGuilds.query({
userId: session.user.id,
});

return (
<Container size="3" mx="4">
<Heading className="mt-rx-8 text-center">Select a server</Heading>
<Grid className="mt-rx-8 gap-rx-4 md:grid-cols-2 lg:grid-cols-3">
<Suspense fallback={<LoadingGuildCard />}>
{discord?.guilds?.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</Suspense>
</Grid>
</Container>
);
}
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { getServerAuthSession } from "@/server/auth";
import { api } from "@/trpc/server";
import { Container, Grid, Heading } from "@radix-ui/themes";
import GuildCard, { LoadingGuildCard } from "@/app/_components/GuildCard";

export default async function Page() {
const session = await getServerAuthSession();
if (!session || !session.user) {
redirect("/");
}
const discord = await api.discord.getGuilds.query({
userId: session.user.id,
});

return (
<Container size="3" mx="4">
<Heading className="mt-rx-8 text-center">Select a server</Heading>
<Grid className="mt-rx-8 gap-rx-4 md:grid-cols-2 lg:grid-cols-3">
<Suspense fallback={<LoadingGuildCard />}>
{discord?.guilds?.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</Suspense>
</Grid>
</Container>
);
}
8 Replies
lanc3
lanc311mo ago
Ah this is a misuse of Suspense. Here's an example from the next.js docs. You use suspense to wrap child server componts
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'

export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
)
}
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'

export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
)
}
https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
Routing: Loading UI and Streaming | Next.js
Built on top of Suspense, Loading UI allows you to create a fallback for specific route segments, and automatically stream content as it becomes ready.
Aditya Kirad
Aditya Kirad11mo ago
So I can't dynamically create component like I'm doing in the code Well I tried passing a default single component do I have to pass named component instead you there @lanc3
lanc3
lanc311mo ago
yes, that's best practice for server components. Really you'd just need to do
"use server";

const Guilds = async () => {
const session = await getServerAuthSession();
if (!session || !session.user) {
redirect("/");
}
const discord = await api.discord.getGuilds.query({
userId: session.user.id,
});

return (
<>
{discord?.guilds?.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</>
);
}
"use server";

const Guilds = async () => {
const session = await getServerAuthSession();
if (!session || !session.user) {
redirect("/");
}
const discord = await api.discord.getGuilds.query({
userId: session.user.id,
});

return (
<>
{discord?.guilds?.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</>
);
}
then
<Container size="3" mx="4">
<Heading className="mt-rx-8 text-center">Select a server</Heading>
<Grid className="mt-rx-8 gap-rx-4 md:grid-cols-2 lg:grid-cols-3">
<Suspense fallback={<LoadingGuildCard />}>
<Guilds />
</Suspense>
</Grid>
</Container>
<Container size="3" mx="4">
<Heading className="mt-rx-8 text-center">Select a server</Heading>
<Grid className="mt-rx-8 gap-rx-4 md:grid-cols-2 lg:grid-cols-3">
<Suspense fallback={<LoadingGuildCard />}>
<Guilds />
</Suspense>
</Grid>
</Container>
Aditya Kirad
Aditya Kirad11mo ago
so it would not work If I will pass defaualt exported component right
lanc3
lanc311mo ago
Not too sure what you mean by that, I'd just make a component file for guilds, and the Page function can stay the same with the imported server component with migrated async calls
Aditya Kirad
Aditya Kirad11mo ago
I understood what I have to do fetch the data in the component not in the page itself right
lanc3
lanc311mo ago
Aditya Kirad
Aditya Kirad11mo ago
thanks I will try it if it works I will tell you but fetching the data in the page itself why doesn't work @lanc3 thank you so much it worked @lanc3 can you help me with one more thing so with tanstack query when fetch some data and when window goes out of focus and then comes back to focus it revalidate the data how can we get the same behaviour here
Want results from more Discord servers?
Add your server