Learn Next.js: Streaming - Newbie question!
Unanswered
Philippine Crocodile posted this in #help-forum
Philippine CrocodileOP
Hi everybody!
I'm studying nextJs from nextjs.org/learn, I'm stuck at this lesson: https://nextjs.org/learn/dashboard-app/streaming
I don't understand why it seems that the loading.tsx is not triggered when I refresh my dashboard page (also if I've added the 3sec wait to simulate longer data fetching).
Could someone help me understand what I'm missing?
Thanks!
Here's the query code:
*export async function fetchRevenue() {
try {
// Artificially delay a response for demo purposes.
// Don't do this in production 🙂
console.log('Fetching revenue data...');
await new Promise((resolve) => setTimeout(resolve, 3000));
const data = await sql<Revenue>
console.log('Data fetch completed after 3 seconds.');
return data.rows;
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to fetch revenue data.');
}
}*
Here's the loading.tsx (that is in @/app/dashboard):
export default function Loading() {
return <div>Loading...</div>;
}
I'm studying nextJs from nextjs.org/learn, I'm stuck at this lesson: https://nextjs.org/learn/dashboard-app/streaming
I don't understand why it seems that the loading.tsx is not triggered when I refresh my dashboard page (also if I've added the 3sec wait to simulate longer data fetching).
Could someone help me understand what I'm missing?
Thanks!
Here's the query code:
*export async function fetchRevenue() {
try {
// Artificially delay a response for demo purposes.
// Don't do this in production 🙂
console.log('Fetching revenue data...');
await new Promise((resolve) => setTimeout(resolve, 3000));
const data = await sql<Revenue>
SELECT * FROM revenue
;console.log('Data fetch completed after 3 seconds.');
return data.rows;
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to fetch revenue data.');
}
}*
Here's the loading.tsx (that is in @/app/dashboard):
export default function Loading() {
return <div>Loading...</div>;
}
36 Replies
are you using safari?
Philippine CrocodileOP
nope, chrome!
hmm interesting.
try this: make the loading page bigger. add more text to it, like a few paragraphs. does it work now?
try this: make the loading page bigger. add more text to it, like a few paragraphs. does it work now?
Philippine CrocodileOP
mmh nope, I've changed it this way but still nothing different happens:
export default function Loading() {
return (<h1>Loading.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..</h1>);
}
export default function Loading() {
return (<h1>Loading.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..</h1>);
}
so the reason i said this is because at least on safari, it's observed that the browser ignores the loading screen if it is too small, that's why i told you to try a few paragraphs. try putting two paragraphs of [lipsum](https://lipsum.com/feed/html) there. does it work?
if not, could you upload the code you currently have so i can have a look?
Philippine CrocodileOP
still not working, here the code:
- loading.tsx
export default function Loading() {
return <div>Loading...</div>;
}
- page.tsx
import { Card } from '@/app/ui/dashboard/cards';
import RevenueChart from '@/app/ui/dashboard/revenue-chart';
import LatestInvoices from '@/app/ui/dashboard/latest-invoices';
import { lusitana } from '@/app/ui/fonts';
import { fetchRevenue, fetchLatestInvoices, fetchCardData } from '@/app/lib/data';
export default async function Page() {
const revenue = await fetchRevenue();
const latestInvoices = await fetchLatestInvoices();
const {
totalPaidInvoices,
totalPendingInvoices,
numberOfInvoices,
numberOfCustomers,
} = await fetchCardData();
return (
<main>
<h1 className={
Dashboard
</h1>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
<Card title="Collected" value={totalPaidInvoices} type="collected" />
<Card title="Pending" value={totalPendingInvoices} type="pending" />
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
<Card
title="Total Customers"
value={numberOfCustomers}
type="customers"
/>
</div>
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
<RevenueChart revenue={revenue} />
<LatestInvoices latestInvoices={latestInvoices} />
</div>
</main>
);
}
- layout.tsx
import SideNav from '@/app/ui/dashboard/sidenav';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
<div className="w-full flex-none md:w-64">
<SideNav />
</div>
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
</div>
);
}
- loading.tsx
export default function Loading() {
return <div>Loading...</div>;
}
- page.tsx
import { Card } from '@/app/ui/dashboard/cards';
import RevenueChart from '@/app/ui/dashboard/revenue-chart';
import LatestInvoices from '@/app/ui/dashboard/latest-invoices';
import { lusitana } from '@/app/ui/fonts';
import { fetchRevenue, fetchLatestInvoices, fetchCardData } from '@/app/lib/data';
export default async function Page() {
const revenue = await fetchRevenue();
const latestInvoices = await fetchLatestInvoices();
const {
totalPaidInvoices,
totalPendingInvoices,
numberOfInvoices,
numberOfCustomers,
} = await fetchCardData();
return (
<main>
<h1 className={
${lusitana.className} mb-4 text-xl md:text-2xl
}>Dashboard
</h1>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
<Card title="Collected" value={totalPaidInvoices} type="collected" />
<Card title="Pending" value={totalPendingInvoices} type="pending" />
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
<Card
title="Total Customers"
value={numberOfCustomers}
type="customers"
/>
</div>
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
<RevenueChart revenue={revenue} />
<LatestInvoices latestInvoices={latestInvoices} />
</div>
</main>
);
}
- layout.tsx
import SideNav from '@/app/ui/dashboard/sidenav';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
<div className="w-full flex-none md:w-64">
<SideNav />
</div>
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
</div>
);
}
it looks good to me honestly. nothing wrong with this. im puzzled
try another browser; also try prod mode (pnpm build then pnpm start)
Philippine CrocodileOP
I tried on edge, nothing changed.
Also tried to push on github so that my vercel deploy has been updated, nothing changed.
Same as prod mode
Also tried to push on github so that my vercel deploy has been updated, nothing changed.
Same as prod mode
Only thing I noticed is this: does it relate someway?
Actually I also inserted a log in the Loading() function that's correctly showing. But still nothing showing on the page
Actually I also inserted a log in the Loading() function that's correctly showing. But still nothing showing on the page
okay you don't get loading screen as you expected but what about the dashboard page? do you get it?
Philippine CrocodileOP
yep dashboard page is working perfectly
the fact is that when I refresh the page stays "freezed" until the 3seconds of "fake" data fetching is finished
yeah this is related. static routes don't have loading page because they are served instantly in prod
dashboard page working means everything is working
Philippine CrocodileOP
Ok, I'm actually following the step-by-step learning path here https://nextjs.org/learn/dashboard-app/streaming, so I think I'm missing something? The page shouldn't be "static", Is there something I'm missing to make it dynamic?
Philippine CrocodileOP
actually I'm trying to replicate what the lessons ask to do, but I'm not able to. Is there someone aware of any issues related to this tasks?
Hmm can you run pnpm build and screenshot for me the output? I want to be sure whether it is a static or a dynamic route
Philippine CrocodileOP
it seems all static to me, but actually from what I understood it should be right since it's a ssr the server is rendering and pushing the static content to the frontend, isn't it?
Simply add export const revalidate = 0 to the dashboard page to make it dynamic
Philippine CrocodileOP
now itìs dynamic, but still the page do not render the loading.tsx (it's freezed until the 3secs end)
can you show me your folder structure?
Philippine CrocodileOP
Yep, here it is:
ok now im very confused. whatever you did is correct
does that also happen when you try to run it in prod mode? (pnpm build then pnpm start)
Philippine CrocodileOP
yep, actually in prod mode it seems it doesn't wait at all for the 3seconds delay that I inserted to simulate a slow data fetch
what? it is a dynamic page, it should wait. are you fetching it in the dynamic page or in the layout?
Philippine CrocodileOP
I'm fetching in the layout. Attaching screenshot for more context:
oh yeah that explains it. the loading.tsx wraps only the page.tsx so is only applicable when you fetch inside page.tsx. fetching inside layout.tsx is not covered
Philippine CrocodileOP
sorry I missed the page screenshot.
I have actually those Suspense that are not working also If I put those kind of boundaries
I have actually those Suspense that are not working also If I put those kind of boundaries
<Suspense>
{await foo()}
</Suspense>
doesnt work. But
async function Component() {
await foo()
return …
}
<Suspense>
<Component />
</Suspense>
should work
{await foo()}
</Suspense>
doesnt work. But
async function Component() {
await foo()
return …
}
<Suspense>
<Component />
</Suspense>
should work
Philippine CrocodileOP
thanks for the help. Actually still nothing changed (attached a video)
do you also fetch these things in the layout.tsx? either dashboard/layout.tsx or the root layout.tsx
Philippine CrocodileOP
nope, no fetches elsewhere (attaching screenshot to show that components that have fetch inside are only used in dashboard page.tsx. fetches are only called in this components, that are used only in the dashboard
these components are not used in dashboard/layout.tsx right? then that's weird.
though in any case i suggest just treating this as a nextjs bug and move on in the tutorial, this issue does not prevent you from finishing remaining parts of the tutorial
though in any case i suggest just treating this as a nextjs bug and move on in the tutorial, this issue does not prevent you from finishing remaining parts of the tutorial