在服务器端检索数据并使用Next.js保存在上下文中

anhgbhbe  于 2023-03-02  发布在  其他
关注(0)|答案(4)|浏览(149)

我希望能够从服务器端的API检索数据,并将其加载到React上下文中,以便应用中的任何组件都可以使用。我尝试了各种方法,但似乎没有一种方法能让我完全按照自己的意愿操作。我尝试过的方法包括:
getServerSideProps --这允许我在服务器端检索数据,但只存在于Page组件中,因此如果我希望在每个页面上都可以使用它,并且我不知道用户将访问哪个页面,我需要为每个页面添加逻辑。
getInitialProps in_app. js-我可以将其添加到_app. js组件中,该组件将在服务器端运行,并可以通过上下文提供程序使其对所有组件可用,但问题是它在每个页面上运行,即使在导航客户端时也是如此。我希望能够调用API一次且仅一次,但这似乎不允许。
getInitialProps in_document. js-我可以将此添加到_document. js组件中,该组件只在服务器上运行,这似乎解决了为每个页面调用它的问题,但我无法弄清楚如何从那里将其存储在React上下文中。我似乎不知道如何在任何地方访问这些数据。看起来_document.js中的getInitialProps是在_app.js中的 * getInitialProps之后调用的。所以我不确定在_app.js中时是否可以使用从_document.js中的getInitialProps生成的值。
如果我在客户机上调用API,有许多方法可以实现这一点,但这对我的用例不起作用,因为当客户机使用来自API的数据进行更新时,它会导致内容 Flink 。
是否有人提出了解决此使用情形的方法?

cnjp1d6j

cnjp1d6j1#

在Next.js中,没有原生函数来a)从API检索数据,B)在服务器上执行,c)使其在每个页面上可用,以及d)仅在用户访问的第一个页面上查询API。
正如您所发现的,getInitialPropsgetServerSideProps将在您每次访问该页面时运行。

  • 但是 *,我们可以让它工作。

如果在初始加载之前需要数据

1.在_app.js中使用getInitialProps从API检索数据
1.将数据加载到_app.js文件内的React上下文中,使其在页面之间持续存在
1.当浏览器获得数据时,创建一个cookie。
1.在getInitialProps中加载后续页面时,检查是否有cookie,如果有,则不检索数据。
在Next.js项目中,有一个相当流行的库nookies可以帮助处理cookie。

如果可以加载页面,则提取数据

_app.js中使用getInitialProps会产生性能成本:你将永远无法创建一个完全静态的页面,这是因为getInitialProps必须在每次页面加载时运行。
如果可以在页面加载之后获取数据,则添加一个API route,然后在上下文提供器中使用useEffect获取数据。

jjhzyzn0

jjhzyzn02#

Next.js 13个以上答案

Next.js实验性应用文件夹现在完全涵盖了这个用例。
1.在React服务器组件(RSC)布局中提取数据
1.在此布局中,使用此值呈现React上下文
1.根据需要在应用程序中使用此上下文
当然,您可以在树中更靠下的RSC中设置这个上下文,例如,如果您只在某个页面或页面的某个组件上需要它。
在这个真实的例子中,我从页面RSC中获取一个调查定义,并通过上下文将其传递给客户端代码。
React服务器组件(此处为页面)的示例代码:

// /app/referer/page.tsx (Server Component)
import { headers } from 'next/headers'
export default async function Page() {
  const headersList = headers()
  const referer = headersList.get('referer')
  return (
    // we set a CLIENT context,
    // based on the SERVER context that we got via headers()
    <RefererProvider value={referer}>
      <InteractiveReferer />
    </RefererProvider>
  )
}

客户端上下文的示例代码:

// /components/InteractiveReferer.tsx (Client Component)
// use "client"
export const InteractiveReferer = () => {
  // this context has been initialized by a parent RSC
  // but we can access it as expected in a Client Component
  const referer = useRefererContext()
  const [clickedReferer, setClickedReferer] = useState(false)
  return (
    <button
      onCLick={() => {
        setClickedReferer(true)
      }}
    >
      Referer: {referer}
    </button>
  )
}

Next.js app文件夹的另一个新奇在于,现在服务器端代码不再局限于页面级getServerSideProps。嵌套组件也可以是服务器组件并触发服务器调用。因此,有时候您可能不仅需要设置客户端上下文,还需要设置一种服务器端上下文,其作用域为当前请求。
I describe this use case extensively,总结一下,可以使用React 18 cache函数(在撰写本文时没有文档)来实现这个目标。
我精心制作了an open source demonstration of this pattern,可以通过以下代码示例进行总结:

import { cache } from "react";

export const getServerContext = cache(() => ({
    // a dummy context for the demonstration
    createdAt: Date.now().toString(),
    calledByLayout: false,
    calledByPage: false,
    calledByNested: false
}))

您可以直接改变返回值以在此上下文中存储新信息。

8fq7wneg

8fq7wneg3#

也许Redux可以解决你的问题,API会触发不必要的消费者重新呈现。

dw1jzc5e

dw1jzc5e4#

您可以尝试使用getInitialPropsin the Page Component itself
这样,数据提取将只针对该页进行。

相关问题