Unsure how to do this pattern in app router

Hey everyone, I'm still getting the hang of using the app router and I've come across something that puzzles me. Suppose I'm retrieving data in a page.tsx file and passing it as props to a component that requires this data. To manage the loading state, I'd typically wrap the component within a <Suspense/> tag. However, it appears <Suspense/> doesn't recognize that the nested component is waiting for data since the data fetching occurs at a higher level in the component tree. Is that correct? It seems like the solution is to move data fetching inside the component itself. However, if I need to render something that specifically requires client-side execution, it would necessitate invoking yet another component. Here's an example to illustrate my point:
// page.tsx
"use server";
export default async function Page() {
const data = await fetchData();

return (
<Suspense fallback={<Loading/>}> // This Suspense is not working here.
<INeedSomeData data={data}/>
</Suspense>
)
}

// INeedSomeData.tsx
"use client";
export const INeedSomeData = ({data}) => {
// Component implementation
}
// page.tsx
"use server";
export default async function Page() {
const data = await fetchData();

return (
<Suspense fallback={<Loading/>}> // This Suspense is not working here.
<INeedSomeData data={data}/>
</Suspense>
)
}

// INeedSomeData.tsx
"use client";
export const INeedSomeData = ({data}) => {
// Component implementation
}
In this setup, <Suspense/> isn't aware that INeedSomeData is awaiting the fetched data. So, I'm thinking the better approach is to have the component fetch its data, like this:
// page.tsx
"use server";
export default async function Page() {
return (
<Suspense fallback={<Loading/>}> // This Suspense now works
<IFetchSomeData />
</Suspense>
)
}

// IFetchSomeData.tsx
"use server";
export const IFetchSomeData= async () => {
const data = await getData();
return (
<IRenderData data={data}/>
)
}

// IRenderData.tsx
"use client";
export const IRenderData = ({data}) => {
// Component implementation
}
// page.tsx
"use server";
export default async function Page() {
return (
<Suspense fallback={<Loading/>}> // This Suspense now works
<IFetchSomeData />
</Suspense>
)
}

// IFetchSomeData.tsx
"use server";
export const IFetchSomeData= async () => {
const data = await getData();
return (
<IRenderData data={data}/>
)
}

// IRenderData.tsx
"use client";
export const IRenderData = ({data}) => {
// Component implementation
}
This works, but this makes it necessary for another nested component. Am I getting this pattern wrong? I'd love some opinions, thanks!
0 Replies
No replies yetBe the first to reply to this messageJoin
Want results from more Discord servers?
Add your server