I’m experimenting with nextjs (coming from react). I think I’m mostly getting things working, but when I create a server component to test fetching on the server side, I’m getting odd results.
Most of the time, when I start the server and load the page the Loading...
message shows all the time. Then if I refresh the page, the data displays as expected. Navigating around the site and returning to the page usually shows the data, but sometimes shows Loading
and if that happens, I have to refresh the page for the data to show again.
I suspect it’s something to do with the nextjs caching, but I’m not sure.
My page component looks like this, roughly stolen from the nextjs documentation:
let statsData: StatsType[];
let url = 'stats';
async function getData() {
const res = await fetchDataServerSide(url);
if (!res.ok) {
throw new Error('Failed to fetch data')
}
await res.json().then(json => {
statsData = json;
})
}
const Dashboard = () => {
const data = getData();
/*if (error) return <div>Failed to load</div>*/
if (!statsData) {
return <div>Loading...</div>
} else {
return (
<div className={"p-6"}>
<div className={"pb-6"}>
<Stats stats={statsData}/>
</div>
</div>
)
}
}
export default Dashboard
my fetchDataServerSide
was just an attempt to abstract the fetch
from each page I need to pull data, since I need to pass in headers each time to work with my laravel API backend:
async function fetchDataServerSide(url: string): Promise<Response> {
'use server'
let fetch_path = process.env.NEXT_PUBLIC_BACKEND_URL + '/api/' + url
const options: RequestInit = {
method: "GET",
headers: {
"Accept": "application/json",
"Referer": process.env.APP_URL,
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/json",
"cookie": "XSRF-TOKEN=" + cookies().get('XSRF-TOKEN').value + ";laravel_session=" + cookies().get('laravel_session').value,
}
}
return await fetch(fetch_path, options);
}
Any thoughts on what I’m doing wrong?
2
Answers
You are not waiting for the data to be fetched. You need to change the "Dashboard" to be an async component and use suspense boundary with a fallback loading UI. It will display loading UI until data needed by the children has been loaded. When the data is loaded, Stats component is rendered with data. The await component is used to wait for the data to be fetched and after fetching, it return the data to the children.
You need to convert Dashboard component to async, it’s ok since it’s a server component.
Then await your getData() to conditionally render your Stats component.
Then, if you want to keep a loading view, you can create a loading.js skeleton in the same route folder :
https://nextjs.org/docs/app/api-reference/file-conventions/loading