Reputation: 333
I'm using Next.JS in an application where I have a Navbar
component that is needed on all pages of the application, and the Navbar
renders data (specifically product-categories
) that must be fetched from my database.
I want this component to be server-side rendered, but since Next.JS only supports page-level SSR and not component-level SSR, it seems that I must use getServerSideProps
on all pages that I want to display this Navbar
and write the same API request in each one, resulting in a ton of repeated logic and API calls across several pages.
While researching how to solve this, I came across React Server Components and wonder if that would be a valid solution for this scenario, but since I'm new to the concept, I'm not sure if I understand it correctly, hence why I'm writing this question.
I'm thinking of doing the following and want to get some feedback as to whether I am on the right track.
My Navbar component would be something like as follows:
const Navbar = () => {
const [data, setData] = useState();
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
const data = await fetch("/api/someEndpoint");
setData(data);
};
return (
<div>
{data.someProperty}
{data.someOtherProperty}
</div>
);
};
export default Navbar;
Then I can create a global Layout
component so that the Navbar is included in all pages, which is where React.Suspense
would be used (if I understand it correctly):
const Layout = ({ children }) => {
return (
<>
<React.Suspense fallback={<FallbackComponent />}>
<Navbar />
<React.Suspense />
{children}
</>
);
};
export default Layout;
Then in _app.tsx
, I would include my Layout
component so that the Navbar
is present everywhere:
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
So here is my question: is this a correct implementation and valid use-case of React.Suspense
? Is component-level data fetching one of the proposed benefits of React Server Components?
Upvotes: 1
Views: 2581
Reputation: 1276
Now with the Next.JS 13 version, you can create an app directory that uses react server components by default.
But you should keep in mind that most of the React hooks like useState and useEffect won't work on server components, also previous Next.js APIs such as getServerSideProps, getStaticProps, and getInitialProps are not supported in the new app directory.
So instead, you can use the new fetch() API that was built on top of the native fetch() Web API. Check the docs for more details.
Upvotes: 1
Reputation: 333
Instead of fetching via an API, you could instead use SSR in _app.tsx
that would pass the data as props to the MyApp
hook. Then the data could be passed down further into the Layout
component, which would again pass it down even further to the Navbar
component. So it would look like something along the lines of this:
// _app.tsx
function MyApp({ /* Props */, data }) {
return (
<Layout data={data}>
<Component {...pageProps} />
</Layout>
);
}
export function getServerSideProps(context) {
// Get data
return {
props: {
data: data
},
}
}
// Layout.tsx
const Layout = ({ children, data }) => {
return (
<>
<Navbar data={data} />
{children}
</>
);
};
export default Layout;
// Navbar.tsx
const Navbar = ({ data }) => {
return (
<div>
{data.someProperty}
{data.someOtherProperty}
</div>
);
};
export default Navbar;
EDIT: SSR in _app.tsx
doesn't work, but I found an answer here: https://stackoverflow.com/a/72325973/12190941
EDIT 2:
You can use getInitalProps
in _app.js
if you want your entire site to be server side rendered. Do keep in mind that this will increase initial load times. I found this example in the Next.js docs here
// _app.js
// ...
MyApp.getInitialProps = async (appContext) => {
// calls page's `getInitialProps` and fills `appProps.pageProps`
const appProps = await App.getInitialProps(appContext);
return { ...appProps }
Upvotes: 0