Suspense Server Component ?
Unanswered
Mini Satin posted this in #help-forum
Mini SatinOP
Hi everyone,
After looking through the documentation : https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
I tried wrapping component A in a Suspense, this component (A) is an async Server Component that fetches data, which contains a Client Component (B) that is wrapping another Server Component (C) using children props. I am fetching data in component A and sending them to A and B. The problem is even using the Suspense at parent level of A, when I request the page, I have to wait 3s before anything appears on screen
Am I using it wrong ? Did I miss something ? Or maybe we can't use Suspense with Server Component that are executing async function such as fetching data.
After looking through the documentation : https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
I tried wrapping component A in a Suspense, this component (A) is an async Server Component that fetches data, which contains a Client Component (B) that is wrapping another Server Component (C) using children props. I am fetching data in component A and sending them to A and B. The problem is even using the Suspense at parent level of A, when I request the page, I have to wait 3s before anything appears on screen
Am I using it wrong ? Did I miss something ? Or maybe we can't use Suspense with Server Component that are executing async function such as fetching data.
4 Replies
Mini SatinOP
Parent ( page.tsx)
Component A ( Server Component )
Component B ( Client Component )
export const dynamic = "force-dynamic";
import Spotify from '@/components/spotify.tsx'
export default function Home() {
return (
<Suspense fallback={<h1>Loading data...</h1>}>
<Spotify />
</Suspense>
);
}Component A ( Server Component )
import SpotifyClientCard from "./SpotifyClientCard";
import SpotifyServerCard from "./SpotifyServerCard";
import { fetchSpotifySchema } from "@/lib/zod/schema";
async function getSpotify() {
try {
const response = await fetch("https://**********/api/spotify");
const responseJson = await response.json();
return fetchSpotifySchema.parse(responseJson);
} catch (err) {
return null;
}
}
export default async function Spotify() {
const data = await getSpotify();
return (
<>
{data ? (
<>
<SpotifyClientCard playedAt={data.playedAt}>
<SpotifyServerCard spotify={data} />
</SpotifyClientCard>
</>
) : (
<></>
)}
</>
);
}Component B ( Client Component )
"use client";
import { motion } from "framer-motion";
const SpotifyClientCard = ({ children, playedAt }: any) => {
return (
<>
<motion.div
initial={{ translateY: 10, opacity: 0 }}
animate={{ translateY: 0, opacity: [0, 1] }}
transition={{ duration: 0.2 }}
className="flex flex-col h-16"
>
{children}
<p>{playedAt}</p>
</motion.div>
</>
);
};
export default SpotifyClientCard;Component C ( Server Component )
import Image from "next/image";
const SpotifyServerCard = ({ spotify }: { spotify: any}) => {
return (
<div className="...">
<a
href={spotify.songUrl}
rel="noopener noreferrer"
target="_blank"
className="h-11 w-11"
>
<Image
src={spotify.albumImageUrl}
alt={spotify.title}
height={50}
width={50}
placeholder="blur"
blurDataURL={spotify.albumImageUrl}
priority
className="..."
/>
</a>
<div className="...">
<a
href={spotify.songUrl}
rel="noopener noreferrer"
target="_blank"
className="..."
title={spotify.title}
>
{spotify.title}
</a>
<p className="...">{spotify.album}</p>
<p className="...">by {spotify.artist}</p>
</div>
</div>
);
};
export default SpotifyServerCard;In this particular case since the fetch data is being used for literally everything and there only one component in the main page.tsx, i would think that suspense wont work very well.
You'll have to use a loading.js instead i think. Since the only thing to fetch here loads data, it will wait till that fetch completes to show you the data directly. You might also want to check dynamic imports
You'll have to use a loading.js instead i think. Since the only thing to fetch here loads data, it will wait till that fetch completes to show you the data directly. You might also want to check dynamic imports
Mini SatinOP
I removed extra code from page.tsx to make it look cleaner, but yeah I will check that thanks for the reply !