I'm trying to lazy load a list of data with suspense and dynamic import in Nextjs. But getting following error:
Error: This Suspense boundary received an update before it finished hydrating. This caused the boundary to switch to client rendering. The usual way to fix this is to wrap the original update in startTransition.
I've tried using startTransition() but couldn't understand how to use it.
DataList.tsx:
import React, { useState } from "react";
interface Props {
data: any[];
}
const DataList = ({ data }: Props) => {
return (
<div>
{data &&
data.map((item) => {
return (
<div key={item._id}>
{item.title}
</div>
);
})}
</div>
);
};
export default DataList;
DataPage.tsx
import React, { Suspense, useEffect, useState } from "react";
import dynamic from "next/dynamic";
const DataList = dynamic(() => import("./DataList"), {
suspense: true,
});
interface Props {}
const Projects = ({}: Props) => {
const [data,setData] = useState<any[]>();
useEffect( () => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(json => setData(json))
} , [])
return (
<>
<Suspense fallback={<p>LOADING</p>}>
<DataList data={data} />
</Suspense>
</>
);
};
export default DataPage;
The error message you're encountering, "This Suspense boundary received an update before it finished hydrating," typically occurs when a Suspense boundary receives an update (in your case, the data prop) before it has finished rendering and hydrating the initial content.
In your code, the issue arises because you're asynchronously loading the DataList component using dynamic import and suspense. However, you're not handling the case where the initial render of DataPage is triggered before the data is fetched and set in the state.
To resolve this issue, you can modify your code as follows:
Add a loading state for the DataPage component:
const [isLoading, setIsLoading] = useState(true);
Update the effect hook to set the loading state to false once the data is fetched:
useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts") .then((response) => response.json()) .then((json) => { setData(json); setIsLoading(false); // Set loading state to false }); }, []);
Use the loading state to conditionally render the DataList component or the fallback content:
return ( <> <Suspense fallback={<p>LOADING</p>}> {isLoading ? ( <p>Loading...</p> // Show a loading message or spinner ) : ( <DataList data={data} /> )} </Suspense> </> );
By incorporating the loading state and conditionally rendering the DataList component based on the loading status, you can ensure that the Suspense boundary does not receive an update before it finishes hydrating.
Remember to adjust the fallback content and loading indicator to match the design and experience you want to provide to your users.
Additionally, make sure you have the necessary setup for Next.js and React to support suspense and dynamic imports properly.