Instantaneous return of Client-side component while doing some Server-side calls
Unanswered
Picardy Spaniel posted this in #help-forum
Picardy SpanielOP
I am using Next.js 14.1
Suppose I have this flow of my server-side component page - how can I return the SkeletonLoader instantly while it is calling database services/3rd party APIs?
const getRecordsToShowFromDb = async (session: Session | null) => {
// Logic for calling database services to fetch records
};
const SomPage = async () => {
let contentToRender = <SkeletonLoader />;
const session = await auth();
const getRecordsToShowFromDbRes = await getRecordsToShowFromDb(session);
const allRecords =
(await getRecordsToShowFromDbRes.json()) as SomeObject[];
const someObject: AnotherObjectType = {};
const someObject2: AnotherObjectType2 = {};
for (const record of allRecords) {
const [locationDetails, displayImage] =
await Promise.all([
someApiServiceFn(allRecords.id);
someApiServiceFn2(allRecords.id);
]);
someObject[allRecords.id] = locationDetails;
someObject2[allRecords.id] = displayImage;
}
if (
allRecords &&
allRecords.length > 0 &&
Object.keys(someObject).length > 0 &&
Object.keys(someObject2).length > 0
) {
contentToRender = (
<div className="flex flex-1 px-4 lg:px-0">
<ListComponentTest {...props} />
</div>
);
}
return contentToRender;
};
export default SomPage;
Suppose I have this flow of my server-side component page - how can I return the SkeletonLoader instantly while it is calling database services/3rd party APIs?
const getRecordsToShowFromDb = async (session: Session | null) => {
// Logic for calling database services to fetch records
};
const SomPage = async () => {
let contentToRender = <SkeletonLoader />;
const session = await auth();
const getRecordsToShowFromDbRes = await getRecordsToShowFromDb(session);
const allRecords =
(await getRecordsToShowFromDbRes.json()) as SomeObject[];
const someObject: AnotherObjectType = {};
const someObject2: AnotherObjectType2 = {};
for (const record of allRecords) {
const [locationDetails, displayImage] =
await Promise.all([
someApiServiceFn(allRecords.id);
someApiServiceFn2(allRecords.id);
]);
someObject[allRecords.id] = locationDetails;
someObject2[allRecords.id] = displayImage;
}
if (
allRecords &&
allRecords.length > 0 &&
Object.keys(someObject).length > 0 &&
Object.keys(someObject2).length > 0
) {
contentToRender = (
<div className="flex flex-1 px-4 lg:px-0">
<ListComponentTest {...props} />
</div>
);
}
return contentToRender;
};
export default SomPage;
4 Replies
@Picardy Spaniel I am using Next.js 14.1
Suppose I have this flow of my server-side component page - how can I return the SkeletonLoader instantly while it is calling database services/3rd party APIs?
const getRecordsToShowFromDb = async (session: Session | null) => {
// Logic for calling database services to fetch records
};
const SomPage = async () => {
let contentToRender = <SkeletonLoader />;
const session = await auth();
const getRecordsToShowFromDbRes = await getRecordsToShowFromDb(session);
const allRecords =
(await getRecordsToShowFromDbRes.json()) as SomeObject[];
const someObject: AnotherObjectType = {};
const someObject2: AnotherObjectType2 = {};
for (const record of allRecords) {
const [locationDetails, displayImage] =
await Promise.all([
someApiServiceFn(allRecords.id);
someApiServiceFn2(allRecords.id);
]);
someObject[allRecords.id] = locationDetails;
someObject2[allRecords.id] = displayImage;
}
if (
allRecords &&
allRecords.length > 0 &&
Object.keys(someObject).length > 0 &&
Object.keys(someObject2).length > 0
) {
contentToRender = (
<div className="flex flex-1 px-4 lg:px-0">
<ListComponentTest {...props} />
</div>
);
}
return contentToRender;
};
export default SomPage;
your style of writing code looks a bit unfamiliar to me. i would separate the long await code into another
async component, then wrap it in a Suspense on page.tsx's content// @file page.tsx
const SomPage = async () => {
const session = await auth();
return <div className="flex flex-1 px-4 lg:px-0">
<Suspense fallback={<SkeletonLoader />}>
<RecordList />
</Suspense>
</div>;
};
export default SomPage;
// @file RecordList.tsx
const getRecordsToShowFromDb = async (session: Session | null) => {
// Logic for calling database services to fetch records
};
const RecordList = async () => {
const allRecords =
await getRecordsToShowFromDbRes.json() as SomeObject[];
const someObject: AnotherObjectType = {};
const someObject2: AnotherObjectType2 = {};
for (const record of allRecords) {
const [locationDetails, displayImage] =
await Promise.all([
someApiServiceFn(allRecords.id);
someApiServiceFn2(allRecords.id);
]);
someObject[allRecords.id] = locationDetails;
someObject2[allRecords.id] = displayImage;
}
return <ListComponentTest {...props} />;
}
export default RecordList;it's important to note that
here I'm using react's
await blocks the code, it does not make a piece of code to run asynchronously.here I'm using react's
Suspense to render components asynchronously, while letting other components in the page.tsx tree to render.a video about react suspense if you're interested to learn more https://www.youtube.com/watch?v=8YQXeqgSSeM
next's official site has a very well-explained docs about the topic as well https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming