跳至內容
文件
進階
效能

效能

SWR 在各種 Web 應用程式中提供關鍵功能,因此**效能**是首要考量。

SWR 內建的**快取**和**重複資料刪除**會跳過不必要的網路請求,但 useSWR hook 本身的效能仍然很重要。在複雜的應用程式中,單一頁面渲染中可能會出現數百個 useSWR 呼叫。

SWR 確保您的應用程式具有

  • 沒有不必要的請求
  • 沒有不必要的重新渲染
  • 沒有匯入不必要的程式碼

且無需您變更任何程式碼。

重複資料刪除

在您的應用程式中重複使用 SWR hook 是很常見的。例如,一個應用程式會渲染目前使用者的頭像 5 次

function useUser () {
  return useSWR('/api/user', fetcher)
}
 
function Avatar () {
  const { data, error } = useUser()
 
  if (error) return <Error />
  if (!data) return <Spinner />
 
  return <img src={data.avatar_url} />
}
 
function App () {
  return <>
    <Avatar />
    <Avatar />
    <Avatar />
    <Avatar />
    <Avatar />
  </>
}

每個 <Avatar> 元件內部都有一個 useSWR hook。由於它們具有相同的 SWR key,並且幾乎同時渲染,**只會發出 1 個網路請求**。

您可以到處重複使用您的資料 hook(例如上述範例中的 useUser),而無需擔心效能或重複的請求。

還有一個 dedupingInterval 選項,可用於覆寫預設的重複資料刪除間隔。

深度比較

SWR 預設會**深度比較**資料變更。如果 data 值沒有變更,則不會觸發重新渲染。

如果您想變更行為,也可以透過 compare 選項自訂比較函式。例如,某些 API 回應會傳回您可能想要從資料差異中排除的伺服器時間戳記。

依賴收集

useSWR 會傳回 4 個**有狀態**的值:dataerrorisLoadingisValidating,每個值都可以獨立更新。例如,如果我們在完整的資料獲取生命週期內印出這些值,它會是像這樣

function App () {
  const { data, error, isLoading, isValidating } = useSWR('/api', fetcher)
  console.log(data, error, isLoading, isValidating)
  return null
}

在最糟的情況下(第一次請求失敗,然後重試成功),您會看到 4 行記錄

// console.log(data, error, isLoading, isValidating)
undefined undefined true true  // => start fetching
undefined Error false false    // => end fetching, got an error
undefined Error true true      // => start retrying
Data undefined false false     // => end retrying, get the data

狀態變更是有意義的。但也表示我們的元件**渲染了 4 次**。

如果我們變更我們的元件,使其只使用 data

function App () {
  const { data } = useSWR('/api', fetcher)
  console.log(data)
  return null
}

奇蹟發生了 — 現在只有 **2 次重新渲染**了

// console.log(data)
undefined // => hydration / initial render
Data      // => end retrying, get the data

內部發生了完全相同的過程,第一次請求出現錯誤,然後我們從重試中取得資料。然而,**SWR 只更新元件使用的狀態**,現在只有 data

如果您不總是使用所有這 3 個狀態,您就已經從這項功能中受益。在 Vercel (在新分頁開啟),這項最佳化可減少約 60% 的重新渲染。

Tree Shaking

SWR 套件是 可 tree-shake (在新分頁開啟) 的,而且沒有副作用。這表示如果您只匯入核心 useSWR API,則像 useSWRInfinite 這種未使用的 API 將不會被綁定到您的應用程式中。