This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
在 Expo Router 应用中使用 React 服务端组件
编辑页面
了解如何在 Expo 中于服务器端渲染 React 组件。
React Server Components 支持许多令人兴奋的能力,包括:
- 使用异步组件和 React Suspense 进行数据获取。
- 使用密钥和服务端 API。
- 用于 SEO 和性能的服务端渲染(SSR)。
- 构建时渲染,以移除未使用的 JS 代码。
Expo Router 在所有平台上都支持 React Server Components。这是该功能的早期 预览,未来将会在 Expo Router 中默认启用。
2 requirements
2 requirements
1.
如果你还没有,请查看 Expo Router 安装指南。
2.
需要 React Native New Architecture,并且从 SDK 52 起默认启用。
用法
要在 Expo 应用中使用 React Server Components,你需要:
-
安装所需的 RSC 依赖:
Terminal -
确保入口模块在 package.json 中是
expo-router/entry(默认)。 -
在项目 app 配置中启用该标志:
- 确保你的 app 配置中的任何位置都没有将
"origin"设置为布尔值。 - 创建一个初始路由 app/index.tsx:
- 创建一个 Server Function actions/render-info.tsx:
Server Function 的视图返回值是一个 React Server Component payload,它将被流式传输到客户端。
在开发者预览期间,app 配置中的
web.output必须为single。更多输出模式的支持即将推出。
服务端组件
服务端组件在服务端运行,这意味着它们可以访问服务端 API 和 Node.js 内置模块(在本地运行时)。它们也可以使用异步组件。
考虑下面这个会获取数据并渲染它的组件:
要将其作为服务端组件渲染,你需要从一个服务端函数中返回它。
重点
- 你不能在服务端组件中使用
useState、useEffect或useContext之类的钩子。 - 你不能在服务端组件中使用浏览器或原生 API。
"use server"并不意味着将文件标记为服务端组件。它用于标记文件中导出了 React 服务端函数。- 服务端组件可以访问所有环境变量,因为它们在客户端之外安全运行。
客户端组件
由于 Server Components 不能访问原生 API 或 React Context,你可以创建一个 Client Component 来使用这些特性。它们通过在文件顶部添加 "use client" 指令来创建。
这个模块可以在 Server Function 或 Server Component 中导入并使用。
重点
你不能向 Server Components 传递函数作为 props。你只能传递可序列化的数据。
React 服务器函数
服务器函数是在服务器上运行,并且可以从客户端组件中调用的函数。可以把它们看作更易编写的、完全类型化的 API 路由。
它们必须始终是一个 async 函数,并且在函数顶部用 "use server" 标记。
你可以创建一个客户端组件来调用这个服务器函数:
服务器函数也可以定义在一个独立文件中(在顶部带有 "use server"),然后从客户端组件中导入:
它们可以在客户端组件中这样使用:
重点
- 作为参数传给服务器函数时,你只能传递可序列化的数据。
- 服务器函数只能返回可序列化的数据。
- 服务器函数在服务器上运行,是放置那些不应暴露给客户端的逻辑的好地方。
- 服务器函数目前不能在 DOM 组件内部使用。
在服务器函数中渲染
Expo Router 中的 React 服务器函数可以在服务器上渲染 React 组件,并将一个 RSC 负载(由 React 团队维护的一种自定义 JSON 风格格式)流式返回,用于在客户端渲染。这类似于 Web 上的服务端渲染(SSR)。
例如,下面的服务器函数会渲染一些文本:
这个服务器函数可以从客户端组件中调用,内容将流式返回到客户端:
库兼容性
并非所有库都已针对 React Server Components 进行优化。你可以使用 "use client" 指令将文件标记为 Client Component,并在 Server Component 中使用它。这可以用来临时规避兼容性问题。
例如,考虑一个还没有附带 "use client" 指令的库 react-native-unoptimized。你可以通过创建一个模块并逐个重新导出这些模块来规避:
避免使用 export * from '...',因为这会破坏 server 和 client 之间互操作的一些内部机制。
在 Server Components 中,带有 "use client" 的模块不能通过点语法访问。这意味着像 StyleSheet.create 或 Platform.OS 这样的操作在没有 react-native 包中进一步优化的情况下将无法在服务器上工作。
Suspense
你可以使用 React Suspense,在等待数据加载时从服务器流式返回部分 UI。
在下面的示例中,客户端会立即返回 加载中... 文本,而当 <MediumTask> 在一秒后完成渲染时,它会将文本替换为 中等任务完成!。<ExpensiveTask> 需要三秒才能加载,完成后会将文本替换为 耗时任务完成!。
如果你移除 <ExpensiveTask> 外层的 Suspense 包裹,你会发现 加载中... 会等待这两个组件都渲染完成后才更新 UI。这使你能够逐步控制加载状态。有时候,一次性等待所有内容加载完成是有意义的(大多数情况下),而在其他时候,只要有内容就尽快流式返回 UI 会更有帮助(比如 ChatGPT 中的文本响应)。
密钥
Server Components 可以访问密钥和服务端 API。你可以使用 process.env 对象来访问环境变量。你可以在项目中导入 server-only 模块,以确保某个模块永远不会在客户端运行。
你可以在 .env 文件中定义密钥:
你无需重启开发服务器即可更新环境变量。它们会在每次请求时自动重新加载。
平台检测
要检测你的代码被打包到哪个平台,请使用 process.env.EXPO_OS 环境变量。例如,process.env.EXPO_OS === 'ios'。相比 Platform.OS,更推荐使用它,因为 react-native 目前还没有为 React Server Components 做完全优化,并且可能无法按预期工作。
你可以通过执行 typeof window === 'undefined' 检查来判断代码是否在服务器上运行。这在客户端设备上总会返回 true,在服务器上返回 false。
使用 jest 进行测试
库作者可以使用 jest-expo 测试其模块是否支持服务器组件。有关更多信息,请参阅测试 React 服务器组件指南。
元数据
React Server Components 是 React 19 的一项特性。为了启用它们,Expo CLI 会在所有平台上自动使用 React 的特殊 canary 构建版本。未来,当 React Native 默认启用 React 19 时,它将被移除。
因此,你可以使用 React 19 的功能,例如在应用中的任意位置放置 <meta> 标签(仅限 web)。
你可以用它来替代 expo-router/head 中的 Head 组件,但目前它仅在 web 上可用。
请求头
你可以使用 expo-router/rsc/headers 模块访问用于向 Server Component 发起请求时所使用的请求头。
unstable_headers 函数返回一个 promise,该 promise 会解析为一个只读的 Headers 对象。
要点
- 该 API 不能与构建时渲染(
render: 'static')一起使用,因为请求头会根据请求动态变化。未来,如果输出模式为static,该 API 将会抛出断言。 unstable_headers仅限服务器端使用,不能在客户端使用。
完整 React Server Components 模式
重要 该模式处于 实验阶段。
启用完整的 React Server Components 支持后,你可以利用更多功能。在此模式下,路由的默认渲染模式是 Server Components,而不是 Client Components。它仍在开发中,因为路由器和 React Navigation 需要重写以支持并发。
要启用完整的 Server Components 模式,你需要在 app 配置中启用 reactServerComponentRoutes 标志:
启用后,所有路由默认都会以 Server Components 的形式渲染。未来,这将减少服务端/客户端之间的瀑布式请求,并启用构建时渲染以提供更好的离线支持。
- 目前没有栈式路由。自定义布局、
Stack、Tabs和Drawer目前都还不支持 Server Components。 - 大多数
Link组件属性目前也不支持。
重新加载 Server Components
这仅限于完整 React Server Components 模式。
Server Components 会在开发环境中于每次请求时重新加载。这意味着你可以修改服务器组件,并在客户端运行时中立即看到这些改动反映出来。你可能希望通过程序方式手动触发一次重新加载事件,以便重新获取数据或重新渲染组件。可以通过 useRouter 钩子中的 router.reload() 函数来实现。
如果该路由是在构建时渲染的,那么它不会在客户端重新渲染。这是因为渲染代码并未包含在生产服务器中。
构建时渲染
这仅限于完整 React Server Components 模式。
Expo Router 支持两种不同的 Server Components 渲染模式:构建时渲染和请求时渲染。可以通过使用 unstable_settings 导出,在每个路由的基础上指定这些模式:
render: 'static'会在构建时渲染该组件,并且在生产环境中永远不会重新渲染它。这类似于传统静态站点生成器的工作方式。render: 'dynamic'会在请求时渲染该组件,并在每次请求时重新渲染它。这类似于服务端渲染的工作方式。
如果你想要客户端渲染,请将数据获取移动到 Client Component,并在本地控制渲染。
标记为 static 输出的路由会在构建时渲染,并嵌入到原生二进制文件中。这使得无需向服务器发起请求即可渲染路由(因为服务器请求已在应用被下载时完成)。
当前默认值是 dynamic 渲染。未来,我们会让缓存和优化变得更智能、更自动化。
你可以使用 generateStaticParams 函数在构建时生成静态页面。这对于只能在构建时运行而不能在服务器上运行的组件很有用。
CSS
这仅限于完整 React Server Components 模式。
Expo Router 支持在 Server Components 中导入全局 CSS 和 CSS 模块。
CSS 会从服务器提升到客户端 bundle 中。
部署
通用 React Server Components 仍处于 beta 阶段。
Web
首先,构建 Web 项目:
然后你可以使用 npx expo serve 在本地托管它,或者将其部署到云端:
EAS Hosting 是部署你的 Expo API 路由和服务器的最佳方式。
原生
你可以按照服务器部署指南来部署你的原生 React Server Components:
将版本化服务器部署并关联到你的生产原生应用。
已知限制
这是一个非常早期的技术预览版,我们正在积极开发中。
- Expo Snack 不支持捆绑服务端组件。
- EAS Update 目前还不支持服务端组件。
- DOM 组件目前还不能在生产环境中使用 React 服务端函数。
- 生产部署受到限制,目前不建议使用。
- 目前不支持将 RSC 负载服务端渲染为 HTML。这意味着静态输出和服务端输出目前还不能完全正常工作。
generateStaticParams在完整的 React 服务端组件模式下仅部分受支持。- 目前不支持 HTML
form与服务端函数的集成(该功能会自动部分生效,但数据未加密)。 StyleSheet.create和Platform.OS在原生平台上不受支持。请对样式使用标准对象,并使用process.env.EXPO_OS进行平台检测。- 由于 Hermes 运行时的限制,调用其他服务端函数的 React 服务端函数在 Hermes 上不受支持。使用 Static Hermes 后可能会解决此问题。