Next.js:减少数据获取并在页面之间共享数据



我正在寻找在Next.js应用程序中更好地获取数据的解决方案。在这个问题上,我不仅仅是在寻找一个解决方案,我还在寻找多种选择,这样我们就可以看看利弊。

我遇到的问题

现在,我有几个页面都包含一个显示一些静态内容的组件和一个从API获取的动态内容的组件。每个页面在其getInitialProps()中执行fetch(),以获取自己的页面数据,还获取页脚数据,,这对于所有页面都是相同的

这当然是有效的,但是有很多重复的数据获取。页脚数据将始终显示在所有页面上,并且始终相同。API中也很少更改它,因此不需要重新验证数据。

我正在寻找的答案

我不仅仅是想解决这个问题,我还想了解一下未来项目的一些新实践。我喜欢写"显而易见"的代码,所以不寻找太粗糙的解决方案,比如写window对象等。首选依赖性较低的简单解决方案。目标是一个快速的网站。减少网络使用/API调用并不重要。

到目前为止我的想法

这是我提出的可能的解决方案,从简单/显而易见到更复杂。

  1. 在Footer组件(客户端)内部执行提取
  2. 在所有/页上的getInitialProps(服务器端和客户端)中进行提取
  3. 使用HOC在_app.js中提取并挂接到它的getInitialProps(),然后将其添加到props中,这样所有页面都可以使用数据
  4. 使用zeit/swr和数据预取来缓存数据
  5. 使用redux存储全局状态

所有这些"工作",但大多数都会不必要地重新引用数据,和/或增加一些复杂性。以下是我所看到的优点/缺点(数字与上面相同):

  1. 简单!获取代码只在一个地方,它位于使用它的地方。数据是在页面加载后提取的,因此内容"跳转"到视图中。数据总是被重新蚀刻
  2. 简单!数据是在服务器上获取的,因此在呈现页面之前内容是可用的。每一页的数据都会被重新蚀刻。我们必须记住为getInitialProps()中的每个页面获取相同的页脚数据
  3. 我们可以在一个地方进行提取,并将其添加到所有页面道具中,这样页脚数据就可以自动用于所有页面的道具。对于一些人来说,要想容易理解发生了什么可能有点复杂,因为这需要对Next.js/Rect的工作原理有更多的了解。仍然刷新所有页面的数据。我们现在一个接一个地执行两个fetch()调用(首先在_app.js中加载页脚内容,然后在每个页面中获取自定义内容),所以速度更慢
  4. 有点简单。我们甚至可以在JS加载之前就使用预取将数据加载到缓存中。在第一个页面加载之后,我们将快速获取数据。可以在页脚组件中直接获取代码。rel="preload"预取技术不适用于所有类型的预取(例如Sanity的客户端使用groq)。为了避免在初始页面加载后加载数据的"跳跃"内容,我们应该为useSWR()提供initialData,这仍然需要我们在getInitialProps()中获取数据,但只在服务器端这样做就足够了。可以使用新的getServerSideProps()
  5. 我们可以加载数据一次(?),并使其在整个应用程序中可用。快速、更少/无需重新蚀刻。添加外部依赖项。更复杂的是,您必须学习redux,甚至只加载一个共享数据对象

当前解决方案,使用项目符号2中描述的解决方案。

const HomePage = (props) => {
return (
<Layout data={props.footer}>
<Home data={props.page} />
</Layout>
)
}
// Not actual query, just sample
const query = `{
"page": *[_type == "page"][0], 
"footer": *[_type == "footer"][0]
}`
HomePage.getInitialProps = async () => {
const data = await client.fetch(query)
return {
page: data.page
footer: data.footer
}
}
export default HomePage

希望对此有更多的了解。我错过了什么显而易见的东西?

O’right!我在找别的东西的时候发现了这根线。但由于我必须处理类似的问题,我可以给你一些指导,我会尽我所能为你澄清。

因此,您希望在应用程序(页面/组件)中共享一些数据。

  1. Next.js使用应用程序组件初始化页面。您可以覆盖它并控制页面初始化。只需在CCD_ 13目录的根目录中创建CCD_。有关更多信息,请访问此链接:https://nextjs.org/docs/advanced-features/custom-app
  2. 就像您可以在页面中使用getInitialProps从API获取数据一样,您也可以在_app.js中使用相同的方法。因此,我会获取那些我需要在应用程序中共享的数据,并消除我的API调用

好吧,现在我可以想出两种方法在我的应用中共享数据

  1. 使用createContext钩子

1.1.使用createContext挂钩创建DataContext。并用您的<DataContext.Provider>包裹<Component {...pageProps} />。这里有一个代码片段可以给你一个更好的线索:

<DataContext.Provider value={{ userData, footerData, etc... }}>
<Component {...pageProps} />
</DataContext.Provider>

1.2.现在在其他页面/组件中,您可以访问您的DataContext,如下所示:

const { footerData } = useContext(DataContext); 

然后你就可以在前端中进行操作

  1. 使用getInitialProps填充props

2.1。getInitialProps用于异步获取一些数据,然后填充props。则在CCD_ 23中将是相同的情况。

_app.js中的代码应该是这样的:

function MyApp({ Component, pageProps, footerData }) {
//do other stuffs
return (
<Component {...pageProps} footerData={footerData} />
;
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
const footerRes = await fetch('http://API_URL');
const footerData = await footerRes.json(); 
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps, footerData };
};

2.2.现在,在您的页面(而不是组件)中,您可以访问道具,包括您从_app.js共享的道具然后你就可以开始操纵了。

希望我能给你一个线索和方向。享受探索的乐趣。

最新更新