iT邦幫忙

2021 iThome 鐵人賽

DAY 4
0

嗨大家!昨天跟大家分享了四種網頁渲染方式,那今天來講講該怎麼用 Next.js 實作~ 在 Next.js 裡,抓取資料的方式會影響到渲染方式。上一篇提到 Next.js 提供的三個 functions 就是用來抓取資料做預渲染 (產生包含內容資料的 HTML 檔案) 的,我們一起看下去~

注意:想要用這三個 functions 的話,一定要在 Next.js 的 page (頁面) 檔案裡面做 export 喔。

注意:這三個 functions 會在 server (伺服器) 端跑完,因此我們可以在裡面寫後端程式碼,甚至操作資料庫。

Next.js Pre-rendering

getStaticProps (Static Generation)

這 function 會在 build time 的時候跑而抓取所需要的資料,就是當我們執行 npm run build 的時候跑的。這 function 可以回傳 props object (物件) 當該 page 的 props,這 page 需要的資料就透過 props 傳進去的。伺服器跑完這 function 之後,除了產生了 HTML 檔案之外,還會產生了 JSON 檔案。為什麼呢?因為在 client-side (客戶端) 切換頁面的時候,瀏覽器會讀這 JSON 檔案裡面的資料用來顯示 page 內容。

// 在 build time 的時候跑在伺服器端
export async function getStaticProps() {
  // 可以直接抓取資料或是操作資料庫
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    // 傳給該 page 的 props
    props: {
      posts,
    },
    // 過了 10 秒之後,可以重新驗證/重新產生
    revalidate: 10,
  }
}

getStaticProps 接收 context 當 parameter,而 context 包含渲染該 page 的相關資訊,可以在這裡看官方的 docsgetStaticProps 回傳一個物件而裡面包含:

  • props (optional):傳給 page 當該 page 的 props
  • revalidate (optional):實作 ISR 用的,如果設定 false 代表只會 build 一次,就是整個專案跑 npm run build 的時候。如果設定秒數,代表過幾秒之後可以重新 generate (產生) 這 page 做 revalidation (重新驗證) 更新 page 的資料。不過伺服器會先回傳 cache 裡的舊 page 給瀏覽器然後在背後 revalidate 完才回傳最新的 page 給瀏覽器,讓瀏覽器去做更新
  • notFound (optional):找不到資料的時候,決定是否回傳 404 的 status code 與 error page
  • redirect (optional):設定是否要導頁而且導去哪裡,用物件的形式 { destination: string, permanent: boolean } 或是 { destination: string, statusCode: number }

與 SSG 或 ISR 的關係

getStaticProps 會在 build time 的時候跑在伺服器端,把抓取到的資料塞進該 page 對應到的 HTML 檔案,讓 HTML 檔案包含了資料內容,而可以直接丟給瀏覽器去顯示,這就是 SSG。如果設定了 revalidation秒數,該 page 會進行重新驗證/重新產生的過程,這是 ISR。

不過,如果在 dynamic (動態) routes 的 page 裡有用到 getStaticProps,那需要搭配 getStaticPaths 才能正確運作,可以去下一段看看為什麼~

關於 dynamic routes 會在之後解釋喔。

getStaticProps

getStaticPaths (Static Generation)

一樣會在伺服器端 build time 的時候跑的,名字跟上一個 function 也有點像,雖然用途不一樣,可是這兩個 function 常常用在一起。這 function 抓取資料的目的並不是變成網頁的內容,而是用這些資料決定需要產生哪些 dynamic (動態) routes 的 HTML 檔案。

export async function getStaticPaths() {
  return {
    paths: [
      { params: { id: '1' } },
      { params: { id: '2' } }
    ],
    fallback: true, false, or 'blocking'
  };
}

getStaticPaths 回傳一個物件而裡面包含:

  • paths (required):決定要產生哪些 paths 的 HTML 檔案,每個 path 是一個物件包含 params 物件。如果你的 path 是 posts/[id]id 是動態的,那 params 裡面要定義 id 的值。所以上面那段 code 只會去產生兩個 HTML 檔案,pages/posts/1.htmlpages/posts/2.html
  • fallback (required):決定找不到 page 的時候的行為,總共有三種方法
    • true:當 page 不在 paths 裡面,伺服器會回傳一個備份版本的 page,而該 page 可能是空的或是 loading 狀態 (由我們決定),然後伺服器在背後去產生該 page 的 JSON 檔案,等到完成之後再傳給瀏覽器去做顯示,也會把這新產生的 page 放在 CDN 的 cache 裡
    • false:如果該 page 不在 paths 裡面,而找不到該 page 的 HTML 檔案,會拿到 404 error code 而顯示 404 error page
    • 'blocking':當 page 不在 paths 裡面,伺服器會產生該 page 的 HTML 檔案而這段期間瀏覽器是等待的狀態 (白畫面),等到 HTML 檔案產生完才回傳給瀏覽器做顯示。這一次伺服器是採用 SSR 的方式,不過產生完之後,HTML 檔案一樣會被放到 CDN 的 cache 裡

與 SSG 或 ISR 的關係

getStaticPaths 會在 build time 的時候跑在伺服器端,把抓取到的資料決定該產生 dynamic routes 的哪些 paths。這些 paths 再往裡面跑每個 page 的 getStaticProps 產生 HTML 和 JSON 檔案。沒有 getStaticPaths 就不會有 dynamic routes 相關的 page 了!

getStaticPaths

getServerSideProps (Server-side Rendering)

最後一個!這 function 很像 getStaticProps,回傳的值差不多,一樣在伺服器端跑。不一樣的點是它不是 build 的時候跑的,而是每次有 request (請求) 的時候才會跑。跟 getStaticProps 也一樣除了會產生 HTML 檔案之外,還會產生了 JSON 檔案。

export async function getServerSideProps(context) {
  return {
    props: {}, // 傳給該 page 的 props
  }
}

getServerSideProps 接收 context 當 parameter,而 context 包含渲染該 page 的相關資訊,可以在這裡看官方的 docsgetServerSideProps 回傳一個物件而裡面包含:

  • props (optional):傳給 page 當該 page 的 props
  • notFound (optional):找不到資料的時候,決定是否回傳 404 的 status code 與 error page
  • redirect (optional):設定是否要導頁而且導去哪裡,用物件的形式 { destination: string, permanent: boolean } 或是 { destination: string, statusCode: number }

與 SSR 的關係

getServerSideProps 會在每一次的 request time 的時候跑在伺服器端,把抓取到的資料塞進該 page 對應到的 HTML 檔案,讓 HTML 檔案包含了資料內容,而可以直接丟給瀏覽器去顯示,這就是 SSR。產生檔案的過程中,瀏覽器會顯示白畫面,所以使用者可能會覺得顯示很慢,而且 SSR 產生的 HTML 檔案不會自動被 CDN 做 cache (需要特別設定喔~)。

getServerSideProps

Client-side 抓取資料

以上三個 function 都是跑在伺服器端抓取資料,可是如果需要一直更新資料或是不需要 SEO,那其實可以採用 CSR,在 client-side (客戶端) 去抓取資料~ 這部分跟一般在寫 React 需要拿資料的時候一模一樣,可能就是在 useEffect 去抓取資料然後畫面顯示 loading 狀態!

小結

今天講的好像有點多XD
明天跟大家分享 Next.js 中的 pages 與 routing!也就是會講到 dynamic routes 的部分喔 :)
祝大家中秋節快樂!

晚安 <3

看更多


上一篇
#03 No-code 之旅 — 什麼是 SSG、SSR、CSR、ISR?
下一篇
#05 No-code 之旅 — Next.js 的 Pages 與 Routing
系列文
製作你的無程式碼(No-code)個人網頁 ft. Next.js, SWR, 串 Youtube, IG, Github, Notion API ~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
高魁良
iT邦新手 1 級 ‧ 2021-09-19 23:41:44

感謝大大分享!

Jade iT邦新手 5 級 ‧ 2021-09-20 10:30:10 檢舉

希望有幫助!謝謝你~~

我要留言

立即登入留言