如何在Next.js中为共享持久布局的页面仅获取一次服务器端数据?



我有一个持久的布局,需要在服务器端获取数据。由于您只能从页面调用getServerSideProps,因此我的解决方案是从页面获取数据,然后将其传递给我的布局。问题是布局应该跨页面保留,这需要我在每次页面更改时重新获取数据。

文件夹结构:


├── /collection
│   ├──[contractaddress]
│   │  ├── dashboard.tsx
│   │  ├── items.tsx
│   │  ├── analytics.tsx

网址示例:"/collection/0xed5af388653567af2f388e6224dc7c4b3241c544/dashboard">

仪表板、分析和项目都是集合的不同视图,并共享一个CollectionLayout

我已经能够遵循Adam Wathan关于持久布局的指南,这很好用。CollectionLayout中跨视图共享的组件跨不同视图保持状态。

我正在使用getServerSideProps获取有关集合的数据,然后将其传回CollectionLayout如下所示:

Dashboard.getLayout = function getLayout(page: ReactElement) {
return (
<CollectionLayout collection={page.props.collection}>
{page}
</CollectionLayout>
);
};

我遇到了一些问题:

  • 布局不允许获取服务器端数据。虽然我可以在客户端获取布局所需的数据,但我更愿意在服务器端执行此操作,以便我可以将这些数据用于 SEO 目的。
  • 由于我正在获取每个视图(页面)中的布局数据,因此我通过多次调用冗余数据来增加服务器不必要的压力。

我的理想状态是每个 [合约地址] 发出 1 个请求。然后将该数据传递给跨视图保留的CollectionLayout

我确实看到布局(https://nextjs.org/blog/layouts-rfc)有更新。在布局文件中调用getServerSideProps的能力可以解决我的所有问题。

同时,我有什么办法在下一个 12.2.2 中解决这个问题吗?

仪表板.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;

在React 中持久化状态有不同的方法,最好的方法是使用 Redux 或更好的是,将数据作为道具传递,这样每个直接子组件都可以访问来自父组件的数据。请参阅此模板。

将"组件"属性从应用程序传递到布局组件.js

app.jsx

const App = ({ Component, pageProps, seoDataFromGetServerSideProps }) => (
<Layout {...{ pageProps, Component, seoDataFromGetServerSideProps }} />
);

布局.jsx

const Layout = ({ Component, pageProps, seoDataFromGetServerSideProps }) => (
<>
<Head>
{/* pass your SEO data here from seoDataFromGetServerSideProps */}
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta httpEquiv="Content-Type" content="text/html; charSet=utf-8" />
<meta name="theme-color" content={seoDataFromGetServerSideProps.theme} />
<meta name="keywords" content={seoDataFromGetServerSideProps.title} />
<meta httpEquiv="Content-Type" content="text/html; charSet=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content={seoDataFromGetServerSideProps.title} />
</Head>
<HeaderContainer />
<Component {...pageProps} seoDataFromGetServerSideProps={seoDataFromGetServerSideProps } />
<FooterContainer />
</>
);
export default Layout;
const HomePage = ({seoDataFromGetServerSideProps }) => (
// return home page 
)
const AboutPage = ({seoDataFromGetServerSideProps }) => (
// return about page 
)

主页和关于页面都将包含您传递的任何内容 布局

我希望你明白这个想法。

最新更新