部分预渲染 3个月前

编程语言
642
部分预渲染

部分预渲染 (Partial Prerendering, PPR) 使你能够将静态和动态组件组合在同一路由中。

在构建过程中,Next.js 会尽可能多地预渲染路由内容。如果检测到动态代码,比如读取传入的请求,你可以用 React Suspense 边界包裹相关组件。然后,Suspense 边界的后备内容将包含在预渲染的 HTML 中。

注意: 部分预渲染是一个实验性功能,可能会发生变化。它尚未准备好用于生产环境。

image

** 观看:** 为什么使用 PPR 及其工作原理 → YouTube (10分钟)

1. 背景

PPR 使你的 Next.js 服务器能够立即发送预渲染的内容。

为了防止客户端到服务器的延迟,动态组件会在服务器上并行流式传输,同时提供初始的预渲染内容。这确保动态组件可以在客户端 JavaScript 加载到浏览器之前开始渲染。

为了避免为每个动态组件创建多个 HTTP 请求,PPR 能够将静态预渲染和动态组件组合在一起,形成一个单独的 HTTP 请求。这确保每个动态组件不需要多个网络往返。

2. 使用部分预渲染

2.1 增量采用(版本 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
// 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>
    </>
  )
}

注意事项

  • 没有 experimental_ppr 的路由将默认设置为 false,不会使用 PPR 进行预渲染。你需要为每个路由明确选择 PPR。
  • experimental_ppr 将应用于路由段的所有子项,包括嵌套的布局和页面。你不需要添加到每个文件中,只需添加到路由的顶层段。
  • 要禁用子段的 PPR,你可以在子段中将 experimental_ppr 设置为 false

2.2 启用 PPR(版本 14)

对于版本 14,你可以通过将 ppr 选项添加到你的 next.config.js 文件中来启用它。这将适用于应用中的所有路由:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    ppr: true,
  },
}

export default nextConfig

3. 动态组件

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 '...'
}

这个组件需要查看传入的请求来读取 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>
  )
}

组件仅在访问值时才会选择动态渲染。

例如,如果你从 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>
  )
}

在表格组件中,访问 searchParams 中的值会使组件动态运行:

// app/table.tsx
export function Table({ searchParams }: { searchParams: { sort: string } }) {
  const sort = searchParams.sort === 'true'
  return '...'
}

4. 处理动态渲染

要确保动态组件能够正确渲染,你需要将其与 React Suspense 结合使用,并在 PPR 环境下对其进行适当配置。这包括对函数、请求和组件的处理,以确保在动态数据加载时能够显示合适的后备内容。

4.1 使用 Suspense 包裹动态组件

在使用 PPR 时,确保将所有动态组件用 Suspense 包裹,以便在动态内容加载期间显示一个后备内容。以下是一个使用 Suspense 包裹动态组件的示例:

// app/page.tsx
import { Suspense } from 'react'
import { DynamicComponent, Fallback } from './dynamic-component'

export const experimental_ppr = true

export default function Page() {
  return (
    <section>
      <h1>This will be prerendered</h1>
      <Suspense fallback={<Fallback />}>
        <DynamicComponent />
      </Suspense>
    </section>
  )
}

4.2 使用动态数据

在动态渲染过程中,你可能需要处理来自请求的动态数据。例如,处理 cookies 或 headers 时,你应确保将其包装在 Suspense 组件中。

// app/dynamic-component.tsx
import { cookies } from 'next/headers'

export function DynamicComponent() {
  const session = cookies().get('session')?.value
  return <div>{session ? `Welcome back, ${session}` : 'Please log in'}</div>
}

4.3 处理嵌套组件

如果你的动态数据需要传递到嵌套组件中,你可以将动态数据作为 prop 传递给子组件。在这种情况下,确保子组件也被适当地处理,并且能够正确渲染动态内容。

// app/page.tsx
import { Suspense } from 'react'
import { Table } from './table'
import { getSearchParams } from './utils'

export const experimental_ppr = true

export default function Page() {
  const searchParams = getSearchParams()
  
  return (
    <section>
      <h1>This will be prerendered</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <Table searchParams={searchParams} />
      </Suspense>
    </section>
  )
}
// app/table.tsx
export function Table({ searchParams }: { searchParams: { sort: string } }) {
  const sort = searchParams.sort === 'true'
  return <div>Sorting by: {sort ? 'ascending' : 'descending'}</div>
}

5. 测试和调试

在使用 PPR 时,确保进行充分的测试,以验证预渲染和动态渲染的效果是否符合预期。调试过程可能需要查看控制台日志、网络请求和组件状态,以确保所有动态内容都能正确加载和渲染。

总结

部分预渲染 (PPR) 是 Next.js 的一个实验性特性,允许将静态和动态内容结合在同一路由中。通过使用 React Suspense 和配置 experimental_ppr 选项,你可以优化页面加载时间和用户体验。请注意,该特性仍在开发中,可能会发生变化,因此在生产环境中使用时请确保测试充分。

如果你有任何问题或需要进一步的帮助,欢迎随时提问!

image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2223507
累计阅读

热门教程文档

MySQL
34小节
Rust
84小节
Next
43小节
Swift
54小节
React Native
40小节