外观
部分预渲染
部分预渲染
部分预渲染(PPR)使您能够在同一路由中结合静态和动态组件。
在构建过程中,Next.js 会尽可能多地预渲染路由。如果检测到动态代码,比如从传入请求中读取数据,您可以使用 React Suspense 边界包装相关组件。Suspense 边界的 fallback 将被包含在预渲染的 HTML 中。
注意
部分预渲染是一个实验性功能,可能会发生变化。它还不适合在生产环境中使用。
🎥 观看: 为什么使用 PPR 以及它是如何工作的 → YouTube (10 分钟)。
背景
PPR 使您的 Next.js 服务器能够立即发送预渲染的内容。
为了防止客户端到服务器的瀑布效应,动态组件在提供初始预渲染的同时开始从服务器并行流式传输。这确保了动态组件可以在浏览器加载客户端 JavaScript 之前开始渲染。
为了避免为每个动态组件创建多个 HTTP 请求,PPR 能够将静态预渲染和动态组件组合到一个 HTTP 请求中。这确保了每个动态组件不需要多次网络往返。
使用部分预渲染
渐进式采用 (版本 15)
在 Next.js 15 中,您可以通过在 next.config.js
中将 ppr
选项设置为 incremental
,并在文件顶部导出 experimental_ppr
路由配置选项,来在布局和页面中逐步采用部分预渲染:
next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
ppr: 'incremental',
},
}
export default nextConfig
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
ppr: 'incremental',
},
}
module.exports = nextConfig
app/page.tsx
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>
</>
};
}
app/page.js
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
。
启用 PPR (版本 14)
在 Next.js 14 中,您可以通过将 ppr
选项添加到您的 next.config.js
文件中来启用它。这将应用于应用程序中的所有路由:
next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
ppr: true,
},
}
export default nextConfig
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
ppr: true,
},
}
module.exports = nextConfig
动态组件
在 next build
期间为您的路由创建预渲染时,Next.js 要求动态函数用 React Suspense 包装。然后,将 fallback
包含在预渲染中。
例如,使用 cookies()
或 headers()
等函数:
app/user.tsx
import { cookies } from 'next/headers'
export function User() {
const session = cookies().get('session')?.value
return '...'
}
app/user.js
import { cookies } from 'next/headers'
export function User() {
const session = cookies().get('session')?.value
return '...'
}
此组件需要查看传入的请求以读取 cookies。要与 PPR 一起使用,您应该用 Suspense 包装组件:
app/page.tsx
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>
)
}
app/page.js
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 转发给另一个组件:
app/page.tsx
import { Table } from './table'
export default function Page({
searchParams,
}: {
searchParams: { sort: string }
}) {
return (
<section>
<h1>This will be prerendered</h1>
<Table searchParams={searchParams} />
</section>
)
}
app/page.js
import { Table } from './table'
export default function Page({ searchParams }) {
return (
<section>
<h1>This will be prerendered</h1>
<Table searchParams={searchParams} />
</section>
)
}
在表格组件内部,访问 searchParams
中的值将使组件动态运行:
app/table.tsx
export function Table({ searchParams }: { searchParams: { sort: string } }) {
const sort = searchParams.sort === 'true'
return '...'
}
app/table.js
export function Table({ searchParams }: {
searchParams: { sort: string }
}) {
const sort = searchParams.sort === 'true';
return '...'
}