跳到內容

after

after 允許您安排在響應(或預渲染)完成後執行的工作。這對於不應阻塞響應的任務和其他副作用非常有用,例如日誌記錄和分析。

它可以在伺服器元件(包括generateMetadata)、伺服器操作路由處理程式代理中使用。

該函式接受一個回撥函式,該函式將在響應(或預渲染)完成後執行。

app/layout.tsx
import { after } from 'next/server'
// Custom logging function
import { log } from '@/app/utils'
 
export default function Layout({ children }: { children: React.ReactNode }) {
  after(() => {
    // Execute after the layout is rendered and sent to the user
    log()
  })
  return <>{children}</>
}

須知: after 不是一個動態 API,呼叫它不會導致路由變為動態。如果它在靜態頁面中使用,回撥將在構建時或頁面重新驗證時執行。

參考

引數

  • 一個回撥函式,將在響應(或預渲染)完成後執行。

持續時間

after 將在平臺的預設或配置的最大路由持續時間內執行。如果您的平臺支援,您可以使用maxDuration路由段配置來配置超時限制。

須知

  • 即使響應未成功完成,after 也會執行。包括丟擲錯誤或呼叫 notFoundredirect 的情況。
  • 您可以使用 React cache 來消除 after 內部呼叫函式的重複。
  • after 可以巢狀在其他 after 呼叫中,例如,您可以建立包裝 after 呼叫的實用函式以新增額外的功能。

示例

使用請求 API

您可以在伺服器操作路由處理程式中的 after 內部使用請求 API,例如cookiesheaders。這對於在變異後記錄活動非常有用。例如:

app/api/route.ts
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
 
export async function POST(request: Request) {
  // Perform mutation
  // ...
 
  // Log user activity for analytics
  after(async () => {
    const userAgent = (await headers().get('user-agent')) || 'unknown'
    const sessionCookie =
      (await cookies().get('session-id'))?.value || 'anonymous'
 
    logUserAction({ sessionCookie, userAgent })
  })
 
  return new Response(JSON.stringify({ status: 'success' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
  })
}

但是,您不能在伺服器元件after 內部使用這些請求 API。這是因為 Next.js 需要知道樹的哪一部分訪問了請求 API 以支援快取元件,但 after 在 React 的渲染生命週期之後執行。

平臺支援

部署選項支援
Node.js 伺服器
Docker 容器
靜態匯出
介面卡平臺特定

瞭解如何在自託管 Next.js 時配置 after

參考:支援無伺服器平臺的 after

在無伺服器上下文中使用 after 需要在傳送響應後等待非同步任務完成。在 Next.js 和 Vercel 中,這是透過一個名為 waitUntil(promise) 的原語實現的,它會延長無伺服器呼叫的生命週期,直到傳遞給waitUntil的所有 promise 都已解決。

如果您希望您的使用者能夠執行 after,您將必須提供您自己的 waitUntil 實現,其行為方式類似。

當呼叫 after 時,Next.js 將像這樣訪問 waitUntil

const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil

這意味著 globalThis[Symbol.for('@next/request-context')] 預期包含一個如下所示的物件:

type NextRequestContext = {
  get(): NextRequestContextValue | undefined
}
 
type NextRequestContextValue = {
  waitUntil?: (promise: Promise<any>) => void
}

這是一個實現示例。

import { AsyncLocalStorage } from 'node:async_hooks'
 
const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()
 
// Define and inject the accessor that next.js will use
const RequestContext: NextRequestContext = {
  get() {
    return RequestContextStorage.getStore()
  },
}
globalThis[Symbol.for('@next/request-context')] = RequestContext
 
const handler = (req, res) => {
  const contextValue = { waitUntil: YOUR_WAITUNTIL }
  // Provide the value
  return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}

版本歷史

版本歷史描述
v15.1.0after 變得穩定。
v15.0.0-rc引入 unstable_after