Next.js 13+ 答案
Next.js 实验性应用程序文件夹现在完美地涵盖了这个用例。
通过 React 上下文将值从 RSC 传递到客户端组件
- 在 React Server Component (RSC) 布局中获取数据
- 在此布局中,使用此值渲染 React 上下文
- 根据需要在您的应用程序中使用此上下文
当然,您可以在树中更下方的 RSC 中设置此上下文,例如,如果您仅在某个页面或页面的某个组件上需要它。
在这个现实生活中的例子中 https://github.com/Devographics/Monorepo/blob/f5c63d45e9e0367c94ab73966b34a1474098085b/surveyform/src/app/%5Blang%5D/survey/%5Bslug%5D/%5Byear%5D/layout.tsx#L111,我在 RSC 页面中获取调查定义,并通过上下文将其传递给客户端代码。我的上下文提供者 https://github.com/Devographics/Monorepo/blob/f5c63d45e9e0367c94ab73966b34a1474098085b/surveyform/src/surveys/components/SurveyContext/Provider.tsx暴露一个类型化的可重用钩子。
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>
)
}
客户端上下文的示例代码(别忘了"use client"
指示):
// /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>
)
}
通过缓存将值从 RSC 传递到其他 RSC
Next.js 应用程序文件夹的另一个新颖之处是,现在服务器端代码不再局限于页面级别getServerSideProps
不再了。嵌套组件也可以是服务器组件并触发服务器调用。因此,有时您可能不仅想设置客户端上下文,还想设置一种服务器端上下文,其范围仅限于当前请求。
I 广泛描述这个用例 https://prismic.io/blog/advanced-nextjs-server-context在本文中。综上所述,可以使用React 18cache
函数(在撰写本文时尚未记录)来实现此目标。
我精心制作了该模式的开源演示 https://github.com/eric-burel/next13-server-context/blob/fd4bd2633aeb9b6c3412d9fb8e829e48de6a5d2a/src/app/getServerContext.ts,可以通过以下代码示例进行总结:
import { cache } from "react";
export const getServerContext = cache(() => ({
// a dummy context for the demonstration
createdAt: Date.now().toString(),
calledByLayout: false,
calledByPage: false,
calledByNested: false
}))
您可以直接改变返回值以在此上下文中存储新信息。
命名注意事项:我一直使用术语“服务器上下文”来指定存储在cache
充当上下文。这是因为它是“客户端”上下文的服务器端等效项。
然而,“请求缓存”可能更合适,因为“服务器上下文”在 Next.js 和 React 的未来版本中可能用于其他目的(在 RSC 和客户端组件之间共享数据)。