將 SWR React Hooks 與 Next.js 的增量靜態再生 (ISR) 結合使用

已發表: 2022-03-10
快速總結 ↬當與 ISR 和 Next.js 的 API 路由配合使用時,SWR 可用於創建響應式用戶體驗。 在本文中,Sam Poder 解釋了 SWR 是什麼,在哪裡使用(以及在哪裡不使用),以及如何使用增量靜態再生來構建網站。

如果您曾經在 Next.js 中使用過增量靜態再生 (ISR),您可能會發現自己正在向客戶端發送陳舊的數據。 當您在服務器上重新驗證頁面時會發生這種情況。 對於某些網站,這是可行的,但對於其他網站(例如 Hack Club 的 Scrapbook,由我幫助維護的 @lachlanjc 構建的網站),用戶希望數據保持最新。

想到的第一個解決方案可能是簡單地在服務器端呈現頁面,確保始終向客戶端發送最新數據。 但是,在渲染之前獲取大量數據會減慢初始頁面加載速度。 Scrapbook 中使用的解決方案是使用 React 掛鉤的 SWR 庫通過客戶端數據獲取從服務器更新緩存頁面。 這種方法可確保用戶仍然擁有良好的體驗、站點速度快並且數據保持最新。

認識 SWR

SWR 是由 Vercel 構建的 React Hooks 庫,名稱來自術語 stale-while-revalidate。 顧名思義,在客戶端通過 SWR 獲取(重新驗證)最新數據時,將為您的客戶端提供陳舊/舊數據。 SWR 不只是重新驗證數據一次,但是,您可以將 SWR 配置為在某個時間間隔內重新驗證數據,當選項卡重新獲得焦點時,當客戶端重新連接到 Internet 或以編程方式。

當與 ISR 和 Next.js 的 API 路由配合使用時,SWR 可用於創建響應式用戶體驗。 首先為客戶端提供緩存的靜態生成頁面(使用getStaticProps()生成),在後台服務器也開始重新驗證該頁面的過程(在此處閱讀更多內容)。 這個過程對客戶來說感覺很快,他們現在可以看到數據集,但是它可能有點過時了。 頁面加載後,將向您的 Next.js API 路由發出獲取請求,該路由返回與使用getStaticProps()生成的數據相同的數據。 當這個請求完成時(假設它成功),SWR 將用這個新數據更新頁面。

現在讓我們回顧一下 Scrapbook 以及它如何幫助解決頁面上存在陳舊數據的問題。 顯而易見的是,現在,客戶端獲得了更新版本。 然而,更有趣的是對我們這邊的速度的影響。 當我們通過 Lighthouse 測量速度時,我們得到站點的 ISR + SWR 變體的速度指數為1.5 秒,服務器端渲染變體的速度指數為5.8 秒(加上有關初始服務器響應時間的警告)。 這兩者之間形成了鮮明的對比(在加載頁面時也很明顯)。 但也有一個權衡,在服務器端渲染頁面上,用戶在幾秒鐘後沒有更改站點佈局,新數據進入。雖然我相信 Scrapbook 可以很好地處理這個更新,但這是一個重要的考慮因素設計您的用戶體驗。

跳躍後更多! 繼續往下看↓

在哪裡使用 SWR(以及在哪裡不使用)

SWR 可以放置在各種地方,以下是 SWR 非常適合的幾個站點類別:

  • 具有需要快速更新的實時數據的站點。
    此類站點的示例是體育比分站點和航班跟踪。 在構建這些站點時,您希望使用間隔設置較低(1 到 5 秒)的 revalidate on interval 選項。
  • 具有實時更新的更新或帖子的提要樣式的站點。
    典型的例子是新聞網站,這些網站有關於選舉等事件的實時博客。 另一個例子也是前面提到的剪貼簿。 在這種情況下,您可能還希望使用 revalidate on interval 選項,但使用更高的間隔設置(30 到 60 秒)以節省數據使用量並防止不必要的 API 調用。
  • 具有更多被動數據更新的站點,人們經常在後台保持打開狀態。
    這些站點的示例是天氣頁面或 2020 年代 COVID-19 病例編號頁面。 這些頁面不會頻繁更新,因此不需要對前兩個示例進行不斷的重新驗證。 但是,它仍然會增強數據更新的用戶體驗。 在這些情況下,我建議重新驗證選項卡重新獲得焦點的日期以及客戶端重新連接到互聯網的日期,這意味著如果一個人焦急地返回水龍頭,希望 COVID 病例只會有小幅增加,他們會快速獲取該數據。
  • 具有用戶可以與之交互的小塊數據的站點。
    想想 Youtube 訂閱按鈕,當您單擊訂閱時,您希望看到計數發生變化並感覺自己有所作為。 在這些情況下,您可以使用 SWR 以編程方式重新驗證數據,以獲取新計數並更新顯示的數量。

需要注意的一件事是,這些都可以在有或沒有 ISR 的情況下應用。

當然,有些地方您不想使用 SWR 或在沒有 ISR 的情況下使用 SWR。 如果您的數據沒有變化或變化很少,SWR 就沒有多大用處,反而會阻塞您的網絡請求並耗盡移動用戶的數據。 SWR 可以處理需要身份驗證的頁面,但是在這些情況下您將希望使用服務器端渲染而不是增量靜態重新生成。

將 SWR 與 Next.js 和增量靜態再生一起使用

現在我們已經探索了這種策略的理論,讓我們探索我們如何將其付諸實踐。 為此,我們將使用政府提供的 API 建立一個網站,顯示新加坡(我住的地方!)有多少出租車。

項目結構

我們的項目將通過三個文件來工作:

  • lib/helpers.js
  • pages/index.js (我們的前端文件)
  • pages/api/index.js (我們的 API 文件)

我們的幫助文件將導出一個函數 ( getTaxiData ),該函數將從外部 API 獲取數據,然後以適當的格式返回以供我們使用。 我們的 API 文件將導入該函數並將其設置為默認導出到將調用getTaxiData函數然後返回它的處理函數,這意味著向/api發送 GET 請求將返回我們的數據。

我們需要 SWR 的這種能力來進行客戶端數據獲取。 最後,在我們的前端文件中,我們將導入getTaxiData並在getStaticProps中使用它,它的數據將傳遞給我們的前端文件的默認導出函數,該函數將呈現我們的 React 頁面。 我們這樣做是為了防止代碼重複並確保數據的一致性。 好拗口,讓我們現在開始編程吧。

助手文件

我們將從在lib/helpers.js中創建getTaxiData函數開始:

 export async function getTaxiData(){ let data = await fetch("https://api.data.gov.sg/v1/transport/taxi-availability").then(r => r.json()) return {taxis: data.features.properties[0].taxi_count, updatedAt: data.features.properties[0].timestamp} }

API 文件

然後我們將在api/index.js中構建處理函數並導入getTaxiData函數:

 import { getTaxiData } from '../../lib/helpers' export default async function handler(req, res){ res.status(200).json(await getTaxiData()) }

除了前面提到的項目結構之外,這裡沒有任何 SWR 或 ISR 獨有的東西。 這些東西現在從index.js開始!

前端文件

我們要做的第一件事就是創建我們的getStaticProps函數! 該函數將導入我們的getTaxiData函數,使用它,然後通過一些額外的配置返回數據。

 export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 } }

我想專注於我們返回的對像中的 revalidate 鍵。 該鍵實際上啟用了增量靜態再生。 它告訴您的主機每秒重新生成靜態頁面是一個可用選項,然後當客戶端訪問您的頁面時,該選項會在後台觸發。 您可以在此處閱讀有關增量靜態再生 (ISR) 的更多信息。

現在是使用 SWR 的時候了! 我們先導入它:

 import useSWR from 'swr'

我們將在我們的 React 渲染函數中使用 SWR,所以讓我們創建該函數:

 export default function App(props){ }

我們從getStaticProps接收道具。 現在我們準備好設置 SWR:

 const fetcher = (...args) => fetch(...args).then(res => res.json()) const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})

讓我們分解一下。 首先,我們定義 fetcher。 這是 SWR 要求的一個參數,以便它知道如何獲取您的數據,因為不同的框架等可以有不同的設置。 在這種情況下,我使用的是 SWR 文檔頁面上提供的功能。 然後我們使用三個參數調用useSWR鉤子:從中獲取數據的路徑、獲取器函數和一個選項對象。

在該options對像中,我們指定了兩件事:

  1. 後備數據;
  2. SWR 應重新驗證數據的時間間隔。

後備數據選項是我們提供從getStaticProps獲取的數據的地方,它確保數據從一開始就可見。 最後,我們使用對象解構從鉤子中提取數據。

最後,我們將使用一些非常基本的 JSX 渲染這些數據:

 return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>

而且,我們做到了! 我們有一個使用 SWR 和增量靜態再生的非常簡單的示例。 (我們示例的源代碼可在此處獲得。)

如果您曾經使用 ISR 遇到過時的數據,您知道該聯繫誰:SWR。

進一步閱讀 SmashingMag

  • SWR React Hooks 庫
  • SWR 簡介:用於遠程數據獲取的 React Hooks,Ibrahima Ndaw
  • ISR 與 DPR:大詞,快速解釋,卡西迪·威廉姆斯
  • Next.js 中的全局與本地樣式,Alexander Dubovoj
  • Next.js 中的客戶端路由,Adebiyi Adedotun Lukman