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

IT技术 reactjs redux fetch next.js sanity
2021-03-23 11:33:54

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

我遇到的问题

现在我有几个页面,它们都包含一个显示静态内容的组件和一个从 API 获取的一些动态内容的组件。每个页面都做一个fetch()在他们getInitialProps()自己的页面数据中,还有页脚数据,这对所有页面都是一样的

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

我正在寻找的答案

我不只是想解决这个问题,我也在寻找一个概述,以便为未来的项目学习一些新的实践。我喜欢编写“明显”的代码,所以不寻找太hacky的解决方案,比如写入window对象等。优先考虑依赖较少的简单解决方案。目标是一个快速的网站。减少网络使用/API 调用并不是那么重要。

到目前为止我的想法

这是我想出的可能的解决方案,从简单/明显到更复杂。

  1. 在页脚组件(客户端)内执行提取
  2. 在所有 /pages 上的 getInitialProps(服务器端和客户端)中获取
  3. 在 _app.js 中使用 HOC 进行 fetch 并挂钩并将其getInitialProps()添加到 props,因此数据可用于所有页面
  4. 使用 zeit/swr 和数据预取来缓存数据
  5. 使用 redux 存储全局状态

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

  1. 👍简单!提取代码仅在一处,它位于使用它的地方。👎 页面加载后获取数据,因此内容“跳转”到查看。数据一直在重新获取。
  2. 👍简单!在服务器上获取数据,因此在呈现页面之前内容可用。👎 为每个页面重新获取数据。我们必须记住为他们的getInitialProps().
  3. 👍 我们可以在一个地方进行 fetch 并将其添加到所有页面 props,因此页脚数据可自动用于所有页面的 props。👎 对于某些人来说,可能会更复杂一些,以便轻松理解正在发生的事情,因为它需要对 Next.js/React 的工作原理有更多的了解。仍然重新获取所有页面的数据。我们现在fetch()依次进行两次调用(首先在 _app.js 中加载页脚内容,然后在每个页面中获取自定义内容),所以它甚至更慢。
  4. 👍 有点简单。我们甚至可以在加载 JS 之前使用预取将数据加载到缓存。在第一页加载后,我们将有快速的数据获取。可以直接在页脚组件中获取代码。👎rel="preload"预取技术不适用于所有类型的提取(例如使用 groq 的 Sanity 客户端)。要对数据进行页面加载完成后加载没有“跳跃”的内容,我们应该提供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

希望对此有更多的了解。我缺少一些明显的东西?

1个回答

哦对了!我在寻找其他东西时发现了这个线程。但是因为我要处理类似的问题,所以我可以给你一些指导,我会尽力为你说清楚。

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

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

嗯,现在我可以想到两种方法来在我的应用程序中共享数据

  1. createContext钩子的使用

1.1. 使用 createContext 挂钩创建 DataContext。<Component {...pageProps} />用您的<DataContext.Provider>. 这是一个代码片段,可以为您提供更好的线索:

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

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

const { footerData } = useContext(DataContext); 

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

  1. 填充props使用getInitialProps

2.1. getInitialProps用于异步获取一些数据,然后填充props. _app.js.

您的代码_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. 现在在您的页面中(而不是在您的组件中),您可以访问props,包括您从中共享的props,_app.js 并且您可以开始进行操作。

希望我能给你一个线索和方向。玩得开心探索。

在 _app 中使用 getInitialProps 的问题是它禁用了自动静态优化。因此所有页面都将在服务器端呈现,这意味着您会错过静态生成页面的好处。来自 Next.js 文档:“注意事项如果您有一个带有 getInitialProps 的自定义应用程序,那么此优化将在没有静态生成的页面中关闭。” - nextjs.org/docs/advanced-features/automatic-static-optimization
2021-05-28 11:33:54
你是对的@i-know-nothing,我无法编辑我的评论,但如果可以,我会修改它说:“所以所有没有明确使用 getStaticProps 的页面都将在服务器端呈现。”
2021-06-01 11:33:54
作为对@EthanRyan 的回应,这只在没有静态生成的页面中禁用它(nextjs.org/docs/basic-features/...),而不是所有页面。使用的页面getStaticProps仍将静态生成。
2021-06-11 11:33:54
如果我想将此数据传递给导航组件怎么办?
2021-06-13 11:33:54
假设您有包含相应组件的索引页。<Header /> <Main /> <Footer /> 您可以访问索引中的道具,现在您要做的就是将其传递给您的组件。所以你可以像这样轻松地处理它: <Header data={props.headerData} /> 并且在 Header 组件中你可以有像 Nav bar 这样的子组件,你现在可以从头数据中提取数据并将其分配给你的 Nav 组件. 所以让我们说这就是你的标题组件中的样子 <Nav data={data.NavData} /> 希望我能给你提供线索。
2021-06-20 11:33:54