iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
Modern Web

React 走出新手村 系列 第 25

React 走出新手村 — Next ISR

  • 分享至 

  • xImage
  •  

ISR概念

ISR(Incremental Static Regeneration)是 Next.js 在(SSG)的基礎上做出的改進方法,讓頁面在構成之後根據需求進行重構,有助於提高網站性能。

ISR 的核心思想是:

  1. 預生成靜態頁面: Next.js 會在建構時生成靜態 HTML 頁面,就像SSG一樣。這些頁面是不會變的,可以被 cache,並可以在不經過server的情況下直接提供給用戶端。
  2. 增量再生成: 與 SSG 不同,ISR 可以讓你在頁面構建之後,依據某些條件觸發頁面的重新生成。也就是說你可以在不重新構建整個網站的情況下,僅重新生成部分頁面。

下面是 ISR 的主要精神:

  • 提高性能: 預先產生靜態頁面可以確保使用者快速載入頁面,因為它們是純靜態的,不需要伺服器運算。
  • 即時性: ISR 允許你根據需要更新頁面,以確保內容的及時性。 例如,在電商網站上,你可以每小時重新產生商品頁面,以顯示最新的庫存和價格。
  • 減少伺服器負擔: 與 SSR 不同,ISR 不需要伺服器為每個請求重新渲染頁面,只有在觸發再生成時才需要伺服器的參與。

實作範例

我們來擴充一下原本範例的功能,讓原本的表單長出各個角色細節的陳列頁面,透過 ISR 來完成以下功能:

  • 在構建時生成列表第一頁範圍的所有角色細節的靜態頁面,讓首次訪問時的用戶可以快速看到畫面。
  • 每當有新的角色細節發布或現有角色更新時,只需重新生成該角色的頁面,而不是整個網站。
// 路徑位置在 src/pages/characters/[id]/index.tsx

import { RickandmortyCharacter } from '@/pages'
import { GetStaticPaths, GetStaticProps } from 'next';
import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'
// 我保留csr的部分讓大家好對比
// const Character = () => {
//   const [roleDetail, setRoleDetail] = useState<RickandmortyCharacter | null>(null)
//   const router = useRouter()
//   useEffect(() => {
//     const controller = new AbortController();
//     const signal = controller.signal;
//     fetch(`https://rickandmortyapi.com/api/character/${router.query.id}`, {
//       signal: signal
//     })
//     .then((response) => response.json())
//     .then((response: RickandmortyCharacter) => {
//       // 成功之後的處理
//       setRoleDetail(response)
//     });
//     return () => controller.abort();
//   }, [router.query.id])
//   return (
//     <div>
//       <h2>here is {router.query.id}</h2>
//       <div>{roleDetail?.name}</div>
//     </div>
//   )
// }

// 下面是SSG/ISR
interface CharacterProps {
  roleDetail: RickandmortyCharacter;
}

const Character: React.FC<CharacterProps> = ({roleDetail}) => {
  const router = useRouter()
  
  return (
    <div>
      <h2>here is {router.query.id}</h2>
      <div>
        <p>Name: {roleDetail?.name}</p>
        <p>status: {roleDetail?.status}</p>
        <p>species: {roleDetail?.species}</p>
        <p>gender: {roleDetail?.gender}</p>
        <p>origin: {roleDetail?.origin.name}</p>
        <p>location: {roleDetail?.location.name}</p>
      </div>
    </div>
  )
}

// 預先生成的路徑
export const getStaticPaths: GetStaticPaths = async () => {
  const numArr = (num: number) => {
    if (num > 0) {
      let result = [];
      for(let i = 1; i <= num; i++) {
        result.push(i)
      }
      return result
    }
  }
	// 這裡我本來就知道第一頁是1 - 20才這樣處理
  const possibleIds = numArr(20);
  
  const paths = possibleIds!.map((id) => ({
    params: { id: id.toString() },
  }));

  return {
    paths,
    fallback: 'blocking',// 可以設定為 false, true, blocking
  };
};

export const getStaticProps: GetStaticProps<CharacterProps> = async ({ params }) => {
  const characterId = params?.id;

  if (!characterId) {
    return {
      notFound: true,
    };
  }

  const response = await fetch(`https://rickandmortyapi.com/api/character/${characterId}`);
  const roleDetail: RickandmortyCharacter = await response.json();

  return {
    props: {
      roleDetail,
    },
    revalidate: 60 // 代表每60秒會重發確認頁面資訊是否有異動需要重新生成
  };
};

export default Character

在這個範例中:

  • getStaticPathsgetStaticProps 用於在構建時生成角色細節的靜態頁面。
  • revalidate 選項表示在每次訪問頁面時,都會檢查是否需要重新生成頁面。

總結

在不考慮 CSR 的情況下,我們只能靠 SSR 或 SSG 來處理,在這兩種情况下,每次有新角色加入或更新時,我們必須重新構建整個網站,來確保所有頁面都是最新的。

不使用 ISR 的情況:

  1. 構建成本高昂: 每次角色更新時都需要重新構建整個網站,有點浪費時間和資源。
  2. 伺服器負載高: 每個請求都需要 server 重新渲染頁面,會增加 server 的負載。
  3. 用戶等待時間: 用戶可能需要等待較長時間,直到網站構建完成,才能看到更新後的內容。

使用 ISR 的情况:

  1. 構建成本降低: 只有角色更新時才需要重構特定的頁面,而不是整個網站。
  2. 伺服器負載減少: 頁面的構建過程在需要時才會發生,伺服器不會頻繁重新渲染頁面。
  3. 用戶等待時間減少: 用戶可以更快看到更新後的内容,因為不需要等待整個網站的重構。

這就是實際使用上的差異,下一篇我們來講講SSR的部分。

給全新手的大禮包

React基本Hook教學


上一篇
React 走出新手村 — Next SSG
下一篇
React 走出新手村 — Next SSR
系列文
React 走出新手村 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言