跳到內容
文件
中介層

中介層

💡

升級到最新版本(≥ 1.0.0)以使用此功能。

中介層功能是 SWR 1.0 中的新功能,可讓您在 SWR Hook 之前和之後執行邏輯。

使用方式

中介層會接收 SWR Hook,並可以在執行之前和之後執行邏輯。如果有多個中介層,則每個中介層都會包裝下一個中介層。列表中的最後一個中介層將接收原始的 SWR Hook useSWR

API

注意:函式名稱不應大寫(例如,myMiddleware 而不是 MyMiddleware),否則 React Lint 規則會拋出 Rules of Hook 錯誤

TypeScript (在新分頁中開啟)

function myMiddleware (useSWRNext) {
  return (key, fetcher, config) => {
    // Before hook runs...
 
    // Handle the next middleware, or the `useSWR` hook if this is the last one.
    const swr = useSWRNext(key, fetcher, config)
 
    // After hook runs...
    return swr
  }
}

您可以將中介層陣列作為選項傳遞給 SWRConfiguseSWR

<SWRConfig value={{ use: [myMiddleware] }}>
 
// or...
 
useSWR(key, fetcher, { use: [myMiddleware] })

擴展

中介層會像一般選項一樣擴展。例如

function Bar () {
  useSWR(key, fetcher, { use: [c] })
  // ...
}
 
function Foo() {
  return (
    <SWRConfig value={{ use: [a] }}>
      <SWRConfig value={{ use: [b] }}>
        <Bar/>
      </SWRConfig>
    </SWRConfig>
  )
}

等同於

useSWR(key, fetcher, { use: [a, b, c] })

多個中介層

每個中介層都會包裝下一個中介層,而最後一個中介層僅包裝 SWR Hook。例如

useSWR(key, fetcher, { use: [a, b, c] })

中介層的執行順序將為 a → b → c,如下所示

enter a
  enter b
    enter c
      useSWR()
    exit  c
  exit  b
exit  a

範例

請求記錄器

讓我們建立一個簡單的請求記錄器中介層作為範例。它會印出由此 SWR Hook 發送的所有提取器請求。您也可以透過將其新增至 SWRConfig,將此中介層用於所有 SWR Hook。

function logger(useSWRNext) {
  return (key, fetcher, config) => {
    // Add logger to the original fetcher.
    const extendedFetcher = (...args) => {
      console.log('SWR Request:', key)
      return fetcher(...args)
    }
 
    // Execute the hook with the new fetcher.
    return useSWRNext(key, extendedFetcher, config)
  }
}
 
// ... inside your component
useSWR(key, fetcher, { use: [logger] })

每次觸發請求時,它都會將 SWR 鍵輸出到主控台

SWR Request: /api/user1
SWR Request: /api/user2

保留先前的結果

有時您希望 useSWR 傳回的資料「延遲」。即使金鑰變更,您仍然希望它傳回先前的結果,直到新資料載入完畢。

這可以與 useRef 一起建置為延遲中介層。在此範例中,我們也會擴展 useSWR Hook 的傳回物件

import { useRef, useEffect, useCallback } from 'react'
 
// This is a SWR middleware for keeping the data even if key changes.
function laggy(useSWRNext) {
  return (key, fetcher, config) => {
    // Use a ref to store previous returned data.
    const laggyDataRef = useRef()
 
    // Actual SWR hook.
    const swr = useSWRNext(key, fetcher, config)
 
    useEffect(() => {
      // Update ref if data is not undefined.
      if (swr.data !== undefined) {
        laggyDataRef.current = swr.data
      }
    }, [swr.data])
 
    // Expose a method to clear the laggy data, if any.
    const resetLaggy = useCallback(() => {
      laggyDataRef.current = undefined
    }, [])
 
    // Fallback to previous data if the current data is undefined.
    const dataOrLaggyData = swr.data === undefined ? laggyDataRef.current : swr.data
 
    // Is it showing previous data?
    const isLagging = swr.data === undefined && laggyDataRef.current !== undefined
 
    // Also add a `isLagging` field to SWR.
    return Object.assign({}, swr, {
      data: dataOrLaggyData,
      isLagging,
      resetLaggy,
    })
  }
}

當您需要 SWR Hook 延遲時,您可以使用此中介層

const { data, isLagging, resetLaggy } = useSWR(key, fetcher, { use: [laggy] })

序列化物件鍵

💡

自 SWR 1.1.0 起,物件類型的鍵將會在幕後自動序列化。

⚠️

在較舊的版本(< 1.1.0)中,SWR 會在每次渲染時淺層比較引數,如果其中任何一個引數已變更,則會觸發重新驗證。如果您傳遞可序列化的物件作為金鑰。您可以序列化物件鍵以確保其穩定性,一個簡單的中介層可以幫助您

function serialize(useSWRNext) {
  return (key, fetcher, config) => {
    // Serialize the key.
    const serializedKey = Array.isArray(key) ? JSON.stringify(key) : key
 
    // Pass the serialized key, and unserialize it in fetcher.
    return useSWRNext(serializedKey, (k) => fetcher(...JSON.parse(k)), config)
  }
}
 
// ...
useSWR(['/api/user', { id: '73' }], fetcher, { use: [serialize] })
 
// ... or enable it globally with
<SWRConfig value={{ use: [serialize] }}>

您不必擔心物件在渲染之間可能會變更。它始終被序列化為相同的字串,而且提取器仍將收到這些物件引數。

💡

此外,您可以使用像 fast-json-stable-stringify (在新分頁中開啟) 而不是 JSON.stringify 的程式庫,速度更快且更穩定。