部分预渲染
注意: 部分预渲染是一项实验性功能,仅在 canary 版本中可用,可能会更改。它尚未准备好用于生产环境。
部分预渲染 (PPR) 使你能够将静态和动态组件组合在同一路由中。
在构建期间,Next.js 会尽可能多地预渲染路由。如果检测到动态代码,例如从传入的请求中读取,你可以使用 React Suspense boundary 包裹相关组件。Suspense boundary 的回退内容将包含在预渲染的 HTML 中。

🎥 观看: 为什么使用 PPR 以及它是如何工作的 → YouTube (10 分钟)。
背景
PPR 使你的 Next.js 服务器能够立即发送预渲染的内容。
为了防止客户端到服务器的瀑布流,动态组件在服务初始预渲染的同时,开始从服务器并行流式传输。这确保了动态组件可以在客户端 JavaScript 加载到浏览器之前开始渲染。
为了防止为每个动态组件创建过多的 HTTP 请求,PPR 能够将静态预渲染和动态组件组合成单个 HTTP 请求。这确保了每个动态组件不需要多次网络往返。
使用部分预渲染
增量采用(版本 15 Canary 版本)
在 Next.js 15 canary 版本中,PPR 作为实验性功能提供。它尚未在稳定版本中提供。要安装
npm install next@canary
你可以在布局和页面中逐步采用部分预渲染,方法是在 next.config.js
中将 ppr
选项设置为 incremental
,并在文件顶部导出 experimental_ppr
路由配置选项
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
ppr: 'incremental',
},
}
export default nextConfig
import { Suspense } from 'react'
import { StaticComponent, DynamicComponent, Fallback } from '@/app/ui'
export const experimental_ppr = true
export default function Page() {
return (
<>
<StaticComponent />
<Suspense fallback={<Fallback />}>
<DynamicComponent />
</Suspense>
</>
)
}
须知:
- 没有
experimental_ppr
的路由将默认为false
,并且不会使用 PPR 进行预渲染。你需要为每个路由显式选择启用 PPR。experimental_ppr
将应用于路由段的所有子项,包括嵌套的布局和页面。你不必将其添加到每个文件,只需添加到路由的顶部段即可。- 要为子段禁用 PPR,你可以在子段中将
experimental_ppr
设置为false
。
动态组件
在 next build
期间为你的路由创建预渲染时,Next.js 要求动态 API 用 React Suspense 包裹。fallback
随后将包含在预渲染中。
例如,使用 cookies 或 headers 等函数
import { cookies } from 'next/headers'
export async function User() {
const session = (await cookies()).get('session')?.value
return '...'
}
此组件需要查看传入的请求以读取 cookies。要将此与 PPR 一起使用,你应该使用 Suspense 包裹组件
import { Suspense } from 'react'
import { User, AvatarSkeleton } from './user'
export const experimental_ppr = true
export default function Page() {
return (
<section>
<h1>This will be prerendered</h1>
<Suspense fallback={<AvatarSkeleton />}>
<User />
</Suspense>
</section>
)
}
组件仅在访问值时选择加入动态渲染。
例如,如果你正在从 page
读取 searchParams
,你可以将此值作为 prop 转发到另一个组件
import { Table } from './table'
export default function Page({
searchParams,
}: {
searchParams: Promise<{ sort: string }>
}) {
return (
<section>
<h1>This will be prerendered</h1>
<Table searchParams={searchParams} />
</section>
)
}
在 table 组件内部,访问 searchParams
中的值将使组件动态运行
export async function Table({
searchParams,
}: {
searchParams: Promise<{ sort: string }>
}) {
const sort = (await searchParams).sort === 'true'
return '...'
}
这有帮助吗?