靜態與動態渲染

在前一章中,您為儀表板總覽頁面擷取了資料。然而,我們簡要討論了當前設置的兩個限制:

  1. 資料請求意外形成了瀑布流 (waterfall)
  2. 儀表板是靜態的,因此任何資料更新都不會反映在您的應用程式中

什麼是靜態渲染?

使用靜態渲染時,資料擷取與渲染會在伺服器端的建置階段(部署時)或重新驗證資料時完成。

當使用者造訪您的應用程式時,會直接提供快取的結果。靜態渲染有幾個優點:

  • 更快的網站 - 預先渲染的內容可以快取,並在部署到 Vercel 等平台時進行全球分發。這確保世界各地的使用者都能更快速可靠地存取您的網站內容。
  • 減輕伺服器負載 - 由於內容已被快取,您的伺服器無需為每個使用者請求動態生成內容。這可以降低運算成本。
  • SEO 優化 - 預先渲染的內容更容易被搜尋引擎爬蟲索引,因為內容在頁面載入時就已準備就緒。這有助於提升搜尋引擎排名。

靜態渲染適用於沒有資料使用者間共享資料的 UI,例如靜態部落格文章或產品頁面。但對於包含個人化資料且需頻繁更新的儀表板來說,可能就不太適合。

靜態渲染的相反是動態渲染。

什麼是動態渲染?

使用動態渲染時,內容會在伺服器端針對每個使用者在請求時(使用者造訪頁面時)進行渲染。動態渲染有幾個優點:

  • 即時資料 - 動態渲染讓您的應用程式能顯示即時或頻繁更新的資料。這非常適合資料經常變動的應用場景。
  • 使用者專屬內容 - 更容易提供個人化內容(如儀表板或使用者個人資料),並根據使用者互動更新資料。
  • 請求時資訊 - 動態渲染讓您能存取僅在請求時才能得知的資訊,例如 cookies 或 URL 搜尋參數。

模擬慢速資料擷取

我們正在建置的儀表板應用程式是動態的。

然而,前一章提到的問題仍然存在:如果某個資料請求比其他請求慢,會發生什麼情況?

讓我們模擬一個慢速資料擷取。在 app/lib/data.ts 中,取消 fetchRevenue() 內的 console.logsetTimeout 註解:

/app/lib/data.ts
export async function fetchRevenue() {
  try {
    // 為了示範目的,我們人為延遲回應
    // 請勿在生產環境這樣做 :)
    console.log('正在擷取收益資料...');
    await new Promise((resolve) => setTimeout(resolve, 3000));
 
    const data = await sql<Revenue[]>`SELECT * FROM revenue`;
 
    console.log('資料擷取完成,耗時 3 秒。');
 
    return data;
  } catch (error) {
    console.error('資料庫錯誤:', error);
    throw new Error('擷取收益資料失敗。');
  }
}

現在在新的分頁中開啟 http://localhost:3000/dashboard/,注意頁面載入時間變長了。在終端機中,您應該會看到以下訊息:

正在擷取收益資料...
資料擷取完成,耗時 3 秒。

這裡我們添加了人為的 3 秒延遲來模擬慢速資料擷取。結果是,在資料擷取期間,整個頁面的 UI 都無法顯示給訪客。這帶出了一個開發者常需解決的挑戰:

使用動態渲染時,您的應用程式速度取決於最慢的資料擷取請求。

On this page