"use client";
import React, { Suspense, useEffect, useState } from "react";
import TopBar from "../components/topBar";
import DataPost from "../components/data";
type User = {
albumId: number;
id: number;
title: string;
url: string;
thumbnailUrl: string;
};
function UsersClient() {
const [users, setUsers] = useState<User[]>([]);
const [error, setError] = useState("");
useEffect(() => {
async function fetchUsers() {
await new Promise((resolve) => setTimeout(resolve, 5000));
try {
const response = await fetch(
";
);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
setUsers(data);
} catch (error) {
setError((error as Error).message);
}
}
fetchUsers();
}, []);
if (error) {
return <div>Error: {error}</div>;
}
return (
<>
<TopBar />
<Suspense fallback={<div>Loading...</div>}>
<div className="grid grid-cols-5">
{users.map((user) => (
<div key={user.id}>
<div className="h-32 w-32 border border-black">
<h1>{user.title}</h1>
<img src={user.url} alt={user.title} />
</div>
</div>
))}
</div>
</Suspense>
</>
);
}
export default UsersClient;
Error
Suspense does not work on nextjs, waiting promise but not displaying loading div
Expected:
displaying loading div
Can someone provide an explanation for why suspense is not functioning in this situation? Loading promise was working fine for 5 seconds, but it was not displaying the loading div.
I'm trying to figure it out, but I'm not able to.
"use client";
import React, { Suspense, useEffect, useState } from "react";
import TopBar from "../components/topBar";
import DataPost from "../components/data";
type User = {
albumId: number;
id: number;
title: string;
url: string;
thumbnailUrl: string;
};
function UsersClient() {
const [users, setUsers] = useState<User[]>([]);
const [error, setError] = useState("");
useEffect(() => {
async function fetchUsers() {
await new Promise((resolve) => setTimeout(resolve, 5000));
try {
const response = await fetch(
"https://jsonplaceholder.typicode/albums/1/photos"
);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
setUsers(data);
} catch (error) {
setError((error as Error).message);
}
}
fetchUsers();
}, []);
if (error) {
return <div>Error: {error}</div>;
}
return (
<>
<TopBar />
<Suspense fallback={<div>Loading...</div>}>
<div className="grid grid-cols-5">
{users.map((user) => (
<div key={user.id}>
<div className="h-32 w-32 border border-black">
<h1>{user.title}</h1>
<img src={user.url} alt={user.title} />
</div>
</div>
))}
</div>
</Suspense>
</>
);
}
export default UsersClient;
Error
Suspense does not work on nextjs, waiting promise but not displaying loading div
Expected:
displaying loading div
Can someone provide an explanation for why suspense is not functioning in this situation? Loading promise was working fine for 5 seconds, but it was not displaying the loading div.
I'm trying to figure it out, but I'm not able to.
Share Improve this question edited Mar 22 at 10:39 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Mar 22 at 10:26 eko prameko pram 654 bronze badges1 Answer
Reset to default 2Couple of things here:
<Suspense>
boundary should be wrapping the component which does the fetching here. (Doc) Here you have only one component. In your case extract another component and do the data fetching in it.<Suspense>
cannot figure out data fetching in effects. (Doc) The data fetching logic should be a part of the component render. In case of Next.js, use something like:
async function fetchUsers() {
await new Promise((resolve) => setTimeout(resolve, 5000));
try {
const response = await fetch(
"https://jsonplaceholder.typicode/albums/1/photos"
);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
return data;
} catch (error) {
//Throw error here
throw error;
}
}
function UsersClient() {
const [users, setUsers] = useState<User[]>([]);
const { users } = await fetchUsers();
return (
<>
<div className="grid grid-cols-5">
{users.map((user) => (
<div key={user.id}>
<div className="h-32 w-32 border border-black">
<h1>{user.title}</h1>
<img src={user.url} alt={user.title} />
</div>
</div>
))}
</div>
);
}
Now basically your wrapper component should have the Suspense
boundary. Something like:
const Parent = () => {
return <>
<TopBar />
<Suspense fallback={<div>Loading...</div>}>
<UsersClient />
</Suspense>
</>
};