Reputation: 1050
I am loading a client component inside a server component but trying to show a fallback loader until the data is fetched inside the client competent via API.
I have the following server component which contains a client component
import { LoggedInUserModel } from "@/models/common/logged-in-user-model";
import { Suspense } from "react";
import dynamic from "next/dynamic";
import ProfileLoading from "./loading22";
const UserProfile = dynamic(() => import("./components/userProfile"), {
ssr: false,
});
const MyProfile = async () => {
const user: LoggedInUserModel = await userService.getUser();
return (
<>
<div className="row mt-3 justify-content-md-center">
<div className="col-12 col-md-8">
<nav
aria-label="breadcrumb"
className="p-3 bg-white rounded-3 shadow-sm mb-4"
>
<ol className="breadcrumb mb-0">
<li className="breadcrumb-item">
<a className="text-decoration-none">
<i className="fa-solid fa-user"></i> My Profile
</a>
</li>
</ol>
</nav>
</div>
<UserProfile user={user} />
</div>
</>
);
};
export default MyProfile;
And my Client Component UserProfile is
"use client";
import { UserProfileModel } from "./../../../../models/User/user-profile-model";
import { Suspense, lazy, use, useEffect, useState } from "react";
import fetchClientData from "@/lib/fetchClientData";
import { LoggedInUserModel } from "@/models/common/logged-in-user-model";
import ProfileLoading from "../loading22";
import React from "react";
const AbcProfile = lazy(() => import("./abcprofile"));
type UserProfileProps = {
user: LoggedInUserModel;
};
const UserProfile = ({ user }: UserProfileProps) => {
return (
<Suspense fallback={<h2>Data loading...........</h2>}>
<AbcProfile />
</Suspense>
);
};
export default UserProfile;
AbcProfile Component:
import { use, useEffect, useState } from "react";
const AbcProfile = () => {
use(
fetch(`/api/user/profile/6490986e0d0ce1756d2b491b`).then((res) =>
res.json()
)
);
return <h2>Data loaded</h2>;
};
export default AbcProfile;
When I run the code it does show the fallback loader but the API is called 4 times to get the data from the server. Why? How to properly use suspense in the client component with nextjs?
Upvotes: 1
Views: 2133
Reputation: 2704
The hybrid mode of a page SSR and component CSR appears to have some limitations. As an example, the Suspense component does not fallback because it thinks that it has rendered the client component. But the client component may be calling the API to load the data. For this hybrid approach, I would use a useEffect hook to call the API, and I would then load the fallback explicitly. When using full SSR or CSR for the page and components, Suspense works as expected.
const UserProfile = ({ user }: UserProfileProps) => {
const [profile, setProfile] = useState(null);
useEffect(() => {
const fetchData = async () => {
const data = fetch(`/api/user/profile/6490986e0d0ce1756d2b491b`).then((res) =>
res.json()
)
setProfile(data);
};
fetchData();
}, []); // Re-fetch query changes)
if (!profile){
return (<h2>Data loading...........</h2>)
}
return (
<h1>{profile.name}</h1>
);
};
Upvotes: 1