I have a persistent layout that needs data to be fetched on the server side. Since you can only call getServerSideProps from a page, my solution is to fetch the data from the page and then pass it to my layout. The issue is that the layout should persist across pages, and this requires me to refetch the data on each page change.
Folder structure:
├── /collection
│ ├──[contractaddress]
│ │ ├── dashboard.tsx
│ │ ├── items.tsx
│ │ ├── analytics.tsx
Example of a URL: "/collection/0xed5af388653567af2f388e6224dc7c4b3241c544/dashboard"
Dashboard, analytics, and items are all different views of a collection, and share a CollectionLayout.
I've been able to follow Adam Wathan's guide on persistent layouts, which has worked great. Components in CollectionLayout which are shared across the views persist state across the different views.
I'm using getServerSideProps to fetch data about the collection and then I pass it back to CollectionLayout like so:
Dashboard.getLayout = function getLayout(page: ReactElement) {
return (
<CollectionLayout collection={page.props.collection}>
{page}
</CollectionLayout>
);
};
I'm running into a few problems:
- Layouts do not allow for sever side data fetching. Although I could fetch the data that the layout needs on the client side, I would prefer to do it on the server side so that I can use that data for SEO purposes.
- Since I am fetching the layout data within each view (page), I am adding unnecessary strain on the server by making multiple calls for redundant data.
My ideal state is to make 1 request per [contractaddress]. That data is then passed to CollectionLayout which persists across views.
I did see that there are updates coming to layouts (https://nextjs.org/blog/layouts-rfc). The ability to call getServerSideProps in a layout file would solve all of my problems.
In the meantime, is there any way for me to get around this in Next 12.2.2?
dashboard.tsx
import { GetServerSideProps } from "next";
import { NextSeo } from "next-seo";
import type { ReactElement } from "react";
import { CollectionLayout } from "../../../../layouts/CollectionLayout";
import type { NextPageWithLayout } from "../../../_app";
type Props = {
collection: {
contractAddress: string;
name: string;
description: string;
image: string;
};
};
const Dashboard: NextPageWithLayout<Props> = ({ collection }) => {
return (
<div className="w-full">
<NextSeo title={collection.name} description={collection.description} />
<div className="bg-purple-400 h-[400px] w-[500px]">Dashboard</div>
</div>
);
};
// This gets called on every request
export const getServerSideProps: GetServerSideProps = async () => {
// This data should only be fetched once and then persisted across views
const res = await fetch("http://localhost:3001/0xed5af388653567af2f388e6224dc7c4b3241c544");
const collection = await res.json();
return { props: { collection: collection } };
};
Dashboard.getLayout = function getLayout(page: ReactElement) {
return (
<CollectionLayout collection={page.props.collection}>
{page}
</CollectionLayout>
);
};
export default Dashboard;