Next.js - 预渲染
Next.js - 数据获取与渲染策略
Section titled “Next.js - 数据获取与渲染策略”Next.js 的一个核心特性是它的预渲染 (pre-render) 能力,这意味着它会提前为每个页面生成 HTML,而不是全部由客户端 JavaScript 完成。预渲染有助于提升性能和 SEO。
Next.js 支持不同的渲染策略,这些策略通常与数据获取结合使用:
1. 静态网站生成 (SSG)
Section titled “1. 静态网站生成 (SSG)”HTML 在构建时 (build time) 生成。然后,这个预渲染的 HTML 会在每个请求时直接从 CDN 提供服务,速度极快。它非常适合内容不会频繁随用户请求而变化的页面(例如,营销页面、博客文章、文档、电子商务产品列表)。
-
无数据: 如果页面不需要外部数据,默认情况下它会自动进行静态生成。
-
带数据 (Pages Router): 在页面文件中使用
getStaticProps异步函数。此函数在构建时运行,获取数据,并将其作为 props 传递给你的页面组件。然后页面会用这些数据进行预渲染。 -
带数据 (App Router): 数据获取通常直接在 Server Components 中使用
async/await进行。默认情况下,Next.js 会积极缓存获取的数据,从而实现静态渲染。你可以通过{ cache: 'no-store' }或{ next: { revalidate: seconds } }等选项来控制缓存行为。 -
增量静态再生 (ISR): SSG 的扩展。它允许你在构建时间之后更新静态页面,而无需进行完整的重新构建。在
getStaticProps(Pages Router) 或fetch选项 (App Router) 中,你可以指定一个revalidate时间。此时间过后,下一个请求将在后台触发页面的重新生成。
2. 服务器端渲染 (SSR)
Section titled “2. 服务器端渲染 (SSR)”页面 HTML 在服务器端为每个请求生成。当页面内容需要保持最新并可能为每个请求进行个性化时,这种方式非常有用(例如,包含用户特定数据的仪表盘,依赖于频繁更新数据的页面)。
-
Pages Router: 使用
getServerSideProps异步函数。此函数在每个请求时运行,获取数据,并在渲染 HTML 之前将其作为 props 传递给页面组件。 -
App Router: 在 Server Components 中使用动态函数(如
next/headers中的cookies()或headers())或配置数据获取选项为cache: 'no-store'或revalidate: 0。这会将路由段启用动态渲染。
3. 客户端渲染 (CSR)
Section titled “3. 客户端渲染 (CSR)”虽然 Next.js 强调服务器端预渲染,但你仍然可以在特定组件中在客户端获取数据,通常使用 React 的 useEffect hook 和数据获取库(如 fetch、axios 或 SWR)。这通常用于页面中可以在初始渲染后加载的部分(例如,缓存页面上的用户特定内容)。
在 App Router 中,使用 useState 或 useEffect 等 hook 的组件必须在文件顶部使用 'use client' 指令标记为 Client Components。
示例 (Pages Router)
Section titled “示例 (Pages Router)”让我们使用 Pages Router 演示 SSG (getStaticProps) 和 SSR (getServerSideProps)。
使用 SSR 的页面 (getServerSideProps):pages/dashboard.js
import Head from 'next/head';
function DashboardPage({ time }) { return ( <> <Head><title>Dashboard (SSR)</title></Head> <h1>Dashboard</h1> <p>This page was rendered on the server at: {new Date(time).toLocaleTimeString()}</p> <p>(Refresh the page to see the time update on each request)</p> </> );}
// 此函数在每个请求时运行export async function getServerSideProps(context) { console.log('getServerSideProps executed for /dashboard'); // 示例:获取用户特定数据或实时信息 // 在这个简单的例子中,我们只获取当前时间 return { props: { time: Date.now() }, // 将作为 props 传递给页面组件 };}
export default DashboardPage;使用 SSG 的页面 (getStaticProps):pages/about.js
import Head from 'next/head';
function AboutPage({ buildTime, repoInfo }) { return ( <> <Head><title>About Us (SSG)</title></Head> <h1>About Us</h1> <p>This page was statically generated at build time.</p> <p>Build timestamp: {new Date(buildTime).toLocaleString()}</p> {repoInfo && ( <div> <h2>Next.js Repo Info (Fetched at Build Time)</h2> <p>Stars: {repoInfo.stargazers_count}</p> <p>Open Issues: {repoInfo.open_issues_count}</p> </div> )} </> );}
// 此函数在构建时(生产环境)运行一次export async function getStaticProps() { console.log('getStaticProps executed for /about'); // 示例:获取页面所需数据 const res = await fetch('https://api.github.com/repos/vercel/next.js'); const repoInfo = await res.json();
return { props: { buildTime: Date.now(), repoInfo: { stargazers_count: repoInfo.stargazers_count || 'N/A', open_issues_count: repoInfo.open_issues_count || 'N/A', } }, // 可选:为增量静态再生 (ISR) 添加 revalidate // revalidate: 60, // 每隔最多 60 秒重新生成一次页面 };}
export default AboutPage;-
运行
npm run build,然后运行npm run start进行生产构建,或者只运行npm run dev进行开发。 -
导航到
/dashboard。多次刷新页面。你会看到时间戳在每次刷新时都更新,表明是 SSR。在开发环境 (npm run dev) 中,getServerSideProps在每个请求时运行。在生产环境中,它也在每个请求时运行。 -
导航到
/about。刷新页面。‘Build timestamp’ 和仓库信息将保持不变(除非启用了 ISR 并且重新验证周期已过),这表明页面是静态生成的。在开发环境中,getStaticProps在每个请求时运行以方便开发,但在生产环境 (npm run build) 中,它只在构建时(或 ISR 重新验证时)运行一次。
选择正确的渲染策略对于性能和用户体验至关重要。尽可能使用 SSG/ISR,只有在必要时才回退到 SSR 或 CSR。