跳到主要內容

use cache

此功能目前在 Canary 版本管道中提供,且可能會變更。請嘗試升級 Next.js,並在 GitHub 上分享您的意見回饋。

use cache 指令會將元件和/或函式指定為可快取。它可以用在檔案頂部,表示檔案中的所有匯出都是可快取的;也可以用在函式或元件頂部內聯,告知 Next.js 應快取傳回值,並在後續請求中重複使用。這是一個實驗性的 Next.js 功能,而不是像 use clientuse server 這樣的原生 React 功能。

用法

使用 next.config.ts 檔案中的 useCache 標記啟用對 use cache 指令的支援

next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    useCache: true,
  },
}
 
export default nextConfig

此外,當設定 dynamicIO 標記時,也會啟用 use cache 指令。

然後,您可以在檔案、元件或函式層級使用 use cache 指令

// File level
'use cache'
 
export default async function Page() {
  // ...
}
 
// Component level
export async function MyComponent() {
  'use cache'
  return <></>
}
 
// Function level
export async function getData() {
  'use cache'
  const data = await fetch('/api/data')
  return data
}

须知

  • use cache 是一個實驗性的 Next.js 功能,而不是像 use clientuse server 這樣的原生 React 功能。
  • 任何傳遞至快取函式的 可序列化 引數(或 props),以及它從父作用域讀取的任何可序列化值,都將轉換為類似 JSON 的格式,並自動成為快取鍵的一部分。
  • 任何不可序列化的引數、props 或封閉值都將變成快取函式內的不透明參考,並且只能傳遞,而不能檢查或修改。這些不可序列化的值將在請求時填入,並且不會成為快取鍵的一部分。
    • 例如,快取函式可以將 JSX 作為 children prop 接收,並傳回 <div>{children}</div>,但它將無法內省實際的 children 物件。
  • 可快取函式的傳回值也必須是可序列化的。這可確保可以正確地儲存和擷取快取資料。
  • 使用 use cache 指令的函式不得有任何副作用,例如修改狀態、直接操作 DOM 或設定計時器以定期執行程式碼。
  • 如果與部分預先渲染一起使用,則具有 use cache 的區段將作為靜態 HTML shell 的一部分進行預先渲染。
  • 與僅支援 JSON 資料的 unstable_cache 不同,use cache 可以快取 React 可以渲染的任何可序列化資料,包括元件的渲染輸出。

範例

使用 use cache 快取整個路由

若要預先渲染整個路由,請將 use cache 新增至 layoutpage 檔案的頂部**兩者**。這些區段中的每一個都會被視為應用程式中的個別進入點,並且將獨立快取。

app/layout.tsx
'use cache'
 
export default function Layout({ children }: { children: ReactNode }) {
  return <div>{children}</div>
}

page 檔案中匯入和巢狀的任何元件都將繼承 page 的快取行為。

app/page.tsx
'use cache'
 
async function Users() {
  const users = await fetch('/api/users')
  // loop through users
}
 
export default function Page() {
  return (
    <main>
      <Users />
    </main>
  )
}

建議先前使用 export const dynamic = "force-static" 選項的應用程式使用此方法,並確保整個路由都經過預先渲染。

使用 use cache 快取元件輸出

您可以在元件層級使用 use cache 來快取在該元件內執行的任何抓取或計算。當您在整個應用程式中重複使用元件時,只要 props 維持相同的結構,它就可以共用相同的快取項目。

props 會被序列化並構成快取鍵的一部分,並且只要序列化的 props 在每個實例中產生相同的值,快取項目就會被重複使用。

app/components/bookings.tsx
export async function Bookings({ type = 'haircut' }: BookingsProps) {
  'use cache'
  async function getBookingsData() {
    const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)
    return data
  }
  return //...
}
 
interface BookingsProps {
  type: string
}

使用 use cache 快取函式輸出

由於您可以將 use cache 新增至任何非同步函式,因此您不僅限於僅快取元件或路由。您可能想要快取網路請求或資料庫查詢,或計算非常緩慢的內容。透過將 use cache 新增至包含此類型工作的函式,它將變成可快取的,並且在重複使用時,將共用相同的快取項目。

app/actions.ts
export async function getData() {
  'use cache'
 
  const data = await fetch('/api/data')
  return data
}

重新驗證

預設情況下,當您使用 use cache 指令時,Next.js 會設定 **15 分鐘的重新驗證週期**。Next.js 設定了接近無限的到期時間,這表示它適用於不需要頻繁更新的內容。

雖然此重新驗證週期對於您不希望經常變更的內容可能很有用,但您可以使用 cacheLifecacheTag API 來設定快取行為

  • cacheLife:用於基於時間的重新驗證週期。
  • cacheTag:用於隨需重新驗證。

這兩個 API 都跨用戶端和伺服器快取層整合,這表示您可以在一個位置設定快取語意,並讓它們應用於所有位置。

請參閱 cacheLifecacheTag 文件以取得更多資訊。

交錯

如果您需要將不可序列化的引數傳遞至可快取函式,您可以將它們作為 children 傳遞。這表示 children 參考可以變更,而不會影響快取項目。

app/page.tsx
export default async function Page() {
  const uncachedData = await getData()
  return (
    <CacheComponent>
      <DynamicComponent data={uncachedData} />
    </CacheComponent>
  )
}
 
async function CacheComponent({ children }: { children: ReactNode }) {
  'use cache'
  const cachedData = await fetch('/api/cached-data')
  return (
    <div>
      <PrerenderedComponent data={cachedData} />
      {children}
    </div>
  )
}

您也可以透過快取元件將伺服器行為傳遞至用戶端元件,而無需在可快取函式內部調用它們。

app/page.tsx
import ClientComponent from './ClientComponent'
 
export default async function Page() {
  const performUpdate = async () => {
    'use server'
    // Perform some server-side update
    await db.update(...)
  }
 
  return <CacheComponent performUpdate={performUpdate} />
}
 
async function CachedComponent({
  performUpdate,
}: {
  performUpdate: () => Promise<void>
}) {
  'use cache'
  // Do not call performUpdate here
  return <ClientComponent action={performUpdate} />
}
app/ClientComponent.tsx
'use client'
 
export default function ClientComponent({
  action,
}: {
  action: () => Promise<void>
}) {
  return <button onClick={action}>Update</button>
}