getStaticProps

如果你從頁面中導出一個名為 getStaticProps 的函數(靜態網站生成),Next.js 將會在建置時使用 getStaticProps 返回的屬性預渲染此頁面。

import type { InferGetStaticPropsType, GetStaticProps } from 'next'

type Repo = {
  name: string
  stargazers_count: number
}

export const getStaticProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetStaticProps<{
  repo: Repo
}>

export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}
export async function getStaticProps() {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}

export default function Page({ repo }) {
  return repo.stargazers_count
}

請注意,無論渲染類型為何,任何 props 都會傳遞到頁面元件,並可以在初始 HTML 中於客戶端查看。這是為了讓頁面能夠正確進行水合 (hydrate)。請確保不要在 props 中傳遞任何不應在客戶端出現的敏感資訊。

何時應該使用 getStaticProps?

在以下情況下,你應該使用 getStaticProps

  • 渲染頁面所需的資料在使用者請求之前就已於建置時可用
  • 資料來自無頭 CMS (headless CMS)
  • 頁面必須預渲染(為了 SEO)且速度非常快 — getStaticProps 會生成 HTMLJSON 文件,兩者都可以透過 CDN 快取以提高效能
  • 資料可以公開快取(非使用者特定)。在某些特定情況下,可以透過使用中介軟體 (Middleware) 來重寫路徑以繞過此條件。

getStaticProps 何時執行

getStaticProps 永遠在伺服器端執行,不會在客戶端執行。你可以使用此工具驗證寫在 getStaticProps 中的程式碼已從客戶端套件中移除。

  • getStaticProps 總是在 next build 期間執行
  • 使用 fallback: true 時,getStaticProps 會在背景執行
  • 使用 fallback: blocking 時,getStaticProps 會在初始渲染前呼叫
  • 使用 revalidate 時,getStaticProps 會在背景執行
  • 使用 revalidate() 時,getStaticProps 會根據需求在背景執行

當與增量靜態生成 (Incremental Static Regeneration) 結合使用時,getStaticProps 會在過期頁面重新驗證期間於背景執行,並將新頁面提供給瀏覽器。

getStaticProps 無法存取傳入的請求(如查詢參數或 HTTP 標頭),因為它生成的是靜態 HTML。如果你需要存取頁面的請求,可以考慮在使用 getStaticProps 的同時使用中介軟體 (Middleware)

使用 getStaticProps 從 CMS 獲取資料

以下範例展示如何從 CMS 獲取部落格文章列表。

// posts 將在建置時由 getStaticProps() 填充
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// 此函數在建置時於伺服器端呼叫。
// 它不會在客戶端呼叫,因此你甚至可以
// 直接進行資料庫查詢。
export async function getStaticProps() {
  // 呼叫外部 API 端點以獲取文章。
  // 你可以使用任何資料獲取函式庫
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 透過返回 { props: { posts } },Blog 元件
  // 將在建置時接收 `posts` 作為屬性
  return {
    props: {
      posts,
    },
  }
}
// posts 將在建置時由 getStaticProps() 填充
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// 此函數在建置時於伺服器端呼叫。
// 它不會在客戶端呼叫,因此你甚至可以
// 直接進行資料庫查詢。
export async function getStaticProps() {
  // 呼叫外部 API 端點以獲取文章。
  // 你可以使用任何資料獲取函式庫
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 透過返回 { props: { posts } },Blog 元件
  // 將在建置時接收 `posts` 作為屬性
  return {
    props: {
      posts,
    },
  }
}

getStaticProps API 參考文件涵蓋了所有可以與 getStaticProps 一起使用的參數和屬性。

直接編寫伺服器端程式碼

由於 getStaticProps 僅在伺服器端執行,因此它永遠不會在客戶端執行。它甚至不會包含在瀏覽器的 JS 套件中,因此你可以直接編寫資料庫查詢而不必擔心它們會被發送到瀏覽器。

這意味著,與其從 getStaticProps 中獲取API 路由(該路由本身從外部來源獲取資料),不如直接在 getStaticProps 中編寫伺服器端程式碼。

以下是一個範例。API 路由用於從 CMS 獲取一些資料,然後該 API 路由直接從 getStaticProps 中呼叫。這會產生額外的呼叫,降低效能。相反,可以透過使用 lib/ 目錄來共享從 CMS 獲取資料的邏輯,然後與 getStaticProps 共享。

lib/load-posts.js
// 以下函數與 getStaticProps 和 API 路由共享
// 來自 `lib/` 目錄
export async function loadPosts() {
  // 呼叫外部 API 端點以獲取文章
  const res = await fetch('https://.../posts/')
  const data = await res.json()

  return data
}
pages/blog.js
// pages/blog.js
import { loadPosts } from '../lib/load-posts'

// 此函數僅在伺服器端執行
export async function getStaticProps() {
  // 與其獲取你的 `/api` 路由,不如直接
  // 在 `getStaticProps` 中呼叫相同的函數
  const posts = await loadPosts()

  // 返回的屬性將傳遞給頁面元件
  return { props: { posts } }
}

或者,如果你沒有使用 API 路由來獲取資料,那麼可以直接在 getStaticProps 中使用 fetch() API 來獲取資料。

要驗證 Next.js 從客戶端套件中移除了哪些程式碼,可以使用 next-code-elimination 工具

靜態生成 HTML 和 JSON

當使用 getStaticProps 的頁面在建置時預渲染時,除了頁面 HTML 文件外,Next.js 還會生成一個包含 getStaticProps 執行結果的 JSON 文件。

此 JSON 文件將透過 next/linknext/router 用於客戶端路由。當你導航到使用 getStaticProps 預渲染的頁面時,Next.js 會獲取此 JSON 文件(在建置時預先計算)並將其用作頁面元件的屬性。這意味著客戶端頁面轉換不會呼叫 getStaticProps,因為只會使用導出的 JSON。

當使用增量靜態生成時,getStaticProps 會在背景執行以生成客戶端導航所需的 JSON。你可能會看到對同一頁面發出的多個請求,但這是預期的行為,不會影響最終使用者的效能。

可以在哪裡使用 getStaticProps

getStaticProps 只能從頁面中導出。你不能從非頁面文件、_app_document_error 中導出它。

這個限制的原因之一是 React 需要在頁面渲染之前擁有所有必需的資料。

此外,你必須將 getStaticProps 作為獨立函數導出 — 如果你將 getStaticProps 作為頁面元件的屬性添加,它將無法工作。

須知:如果你創建了自訂應用程式 (custom app),請確保按照連結文件中的說明將 pageProps 傳遞給頁面元件,否則屬性將為空。

在開發環境中每次請求都會執行

在開發環境中 (next dev),getStaticProps 會在每次請求時呼叫。

預覽模式

你可以使用預覽模式 (Preview Mode) 暫時繞過靜態生成,並在請求時而非建置時渲染頁面。例如,你可能正在使用無頭 CMS,並希望在草稿發布前預覽它們。