【NEXT.JS 系列】基本功能—頁面

Home 教學 【NEXT.JS 系列】基本功能—頁面
【NEXT.JS 系列】基本功能—頁面
Next.js

在 Next.js 中,頁面是從 pages 目錄中的 .js.jsx.ts.tsx 文件匯出的 React 元件。 每個頁面都根據其文件名與一個路由相關聯。

例如:如果您建立匯出 React 元件的 pages/about.js,如下所示,它將可以在 /about 中訪問。

function About() {
  return <div>About</div>
}

export default About

擁有動態路由的頁面

Next.js 支援具有動態路由的頁面。 例如,如果您建立了一個名為 pages/posts/[id].js 的文件,那麼它將可以在 posts/1posts/2 等處訪問。

預先渲染

預設情況下,Next.js 預先渲染每個頁面。 這意味著 Next.js 會提前為每個頁面生成 HTML,而不是全部由客戶端 JavaScript 完成。 預先渲染可以帶來更好的性能和 SEO。

每個生成的 HTML 都與該頁面所需的最少 JavaScript 程式碼相關聯。 當瀏覽器加載頁面時,其 JavaScript 程式碼將運行並使頁面完全可互動。 (這個過程稱為水合作用 hydration。)

兩種預先渲染的形式

Next.js 有兩種預先渲染形式:靜態生成和服務器端渲染。不同之處在於它何時為頁面生成 HTML。

  • 靜態生成 Static Generation(推薦):HTML 在 runtime 建構時生成,並將在每個請求中重複使用。
  • 服務器端渲染 Server-side Rendering:在每個請求上生成 HTML。

重要的是,Next.js 允許您選擇要為每個頁面使用的預先渲染形式。您可以通過對大多數頁面使用靜態生成並為其他頁面使用服務器端渲染來建立“混合”Next.js 應用程式。

出於性能原因,我們建議使用靜態生成而不是服務器端渲染。靜態生成的頁面可以被 CDN 快取,無需額外配置來提高性能。但是,在某些情況下,服務器端渲染可能是唯一的選擇。

您還可以將客戶端渲染與靜態生成或服務器端渲染一起使用。這意味著頁面的某些部分可以完全由客戶端 JavaScript 呈現。要了解更多資訊,請查看數據獲取文件。

靜態生成 (推薦)

如果頁面使用靜態生成,則頁面 HTML 是在建構時生成的。 這意味著在生產中,頁面 HTML 會在您運行 next build 時生成。 然後,此 HTML 將在每個請求上重複使用。 它可以由 CDN 快取。

在 Next.js 中,您可以靜態生成包含或不包含數據的頁面。 讓我們來看看每個案例。

沒有資料的靜態生成

預設情況下,Next.js 使用靜態生成預先渲染頁面而不獲取數據。 這是一個例子:

function About() {
  return <div>About</div>
}

export default About

請注意,此頁面不需要獲取任何要預先渲染的外部數據。 在這種情況下,Next.js 在建構期間為每個頁面生成一個 HTML 文件。

有資料的靜態生成

某些頁面需要獲取外部數據以進行預先渲染。 有兩種情況,可能適用一種或兩種情況。 在每種情況下,您都可以使用 Next.js 提供的這些功能:

  1. 您的頁面內容取決於外部數據:使用 getStaticProps
  2. 您的頁面路徑取決於外部數據:使用 getStaticPaths(通常除了 getStaticProps 之外)。

情境 1:你的頁面內容依賴於外部數據

範例:您的部落格頁面可能需要從 CMS(內容管理系統)獲取部落格文章列表。

// TODO: Need to fetch `posts` (by calling some API endpoint)
//       before this page can be pre-rendered.
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

export default Blog

為了在預先渲染中獲取這些數據,Next.js 允許您從同一個文件中匯出一個名為 getStaticProps 的異步函數。 此函數在建構時被調用,並允許您在預先渲染時將獲取的數據傳遞給頁面的 props

function Blog({ posts }) {
  // Render posts...
}

// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

要了解有關 getStaticProps 工作原理的更多內容,請查看數據獲取文件。

情境 2:您的頁面路徑依賴於外部數據

Next.js 允許您建立具有動態路由的頁面。 例如,您可以建立一個名為 pages/posts/[id].js 的文件來顯示基於 id 的單個部落格文章。 這將允許您在訪問 posts/1 時顯示 id: 1 的部落格文章。

但是,您希望在建構時預先渲染哪個 id 可能取決於外部數據。

例如:假設您只向資料庫添加了一篇文章(id:1)。 在這種情況下,您只想在建構時預先渲染 posts/1

稍後,您可能會添加第二個帶有 id: 2 的文章。然後您還想預先渲染帖子 posts/2

因此,預先渲染的頁面路徑取決於外部數據。 為了處理這個問題,Next.js 允許您從動態頁面(在本例中為 pages/posts/[id].js)導出一個名為 getStaticPaths 的異步函數。 此函數在建構時被調用,並允許您指定要預先渲染的路徑。

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

同樣在 pages/posts/[id].js 中,您需要匯出 getStaticProps 以便您可以使用此 id 獲取有關文章的數據並使用它來預先渲染頁面:

function Post({ post }) {
  // Render post...
}

export async function getStaticPaths() {
  // ...
}

// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // Pass post data to the page via props
  return { props: { post } }
}

export default Post

要了解有關 getStaticPaths 如何工作的更多內容,請查看數據獲取文件。

我什麼時候應該使用靜態生成?

我們建議盡可能使用靜態生成(有數據和無數據),因為您的頁面可以建構一次並由 CDN 提供服務,這比讓服務器在每次請求時呈現頁面要快得多。

您可以將靜態生成用於多種類型的頁面,包括:

  • 營銷頁面
  • 部落格文章和作品集
  • 電子商務產品列表
  • 幫助和文件

您應該問自己:“我可以在用戶請求之前預先渲染此頁面嗎?”如果答案是肯定的,那麼您應該選擇靜態生成。

另一方面,如果您不能在用戶請求之前預先渲染頁面,則靜態生成不是一個好主意。也許您的頁面會顯示頻繁更新的數據,並且頁面內容會隨每個請求而更改。

在這種情況下,您可以執行以下操作之一:

  • 在客戶端渲染中使用靜態生成:您可以跳過預先渲染頁面的某些部分,然後使用客戶端 JavaScript 來填充它們。要了解有關此方法的更多資訊,請查看數據獲取文件。
  • 使用服務器端渲染:Next.js 在每個請求上預先渲染一個頁面。它會更慢,因為頁面無法被 CDN 快取,但預先渲染的頁面將始終是最新的。我們將在下面討論這種方法。

服務器端渲染

也稱為“SSR”或“動態渲染”。

如果頁面使用服務器端呈現,則在每次請求時都會生成頁面 HTML。

要對頁面使用服務器端渲染,您需要匯出一個名為 getServerSideProps 的異步函數。 服務器將在每次請求時調用此函數。

例如,假設您的頁面需要預先渲染頻繁更新的數據(從外部 API 獲取)。 您可以編寫 getServerSideProps 來獲取此數據並將其傳遞給 Page,如下所示:

function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page

如您所見,getServerSideProps 類似於 getStaticProps,但不同之處在於 getServerSideProps 在每個請求上運行,而不是在建構時運行。

要了解有關 getServerSideProps 工作原理的更多內容,請查看數據獲取文件。

總結

我們已經討論了 Next.js 的兩種預先渲染形式。

  • 靜態生成(推薦):HTML 在建構時生成,並將在每個請求中重複使用。 要使頁面使用靜態生成,請匯出頁面元件,或匯出 getStaticProps(如果需要,還可以匯出 getStaticPaths)。 這對於可以在用戶請求之前預先渲染的頁面非常有用。 您還可以將它與客戶端渲染一起使用以引入額外的數據。
  • 服務器端渲染:在每個請求上生成 HTML。 要使頁面使用服務器端渲染,請匯出 getServerSideProps。 因為服務器端渲染導致性能比靜態生成慢,所以只有在絕對必要時才使用它。

相關文章