after
after
を使用すると、レスポンス(またはプリレンダリング)が完了した後に実行する作業をスケジュールできます。これは、ロギングや分析など、レスポンスをブロックすべきではないタスクや副作用に便利です。
サーバーコンポーネント(generateMetadata
を含む)、サーバーアクション、ルートハンドラ、ミドルウェア で使用できます。
この関数は、レスポンス(またはプリレンダリング)が完了した後に実行されるコールバックを受け入れます:
import { after } from 'next/server'
// カスタムロギング関数
import { log } from '@/app/utils'
export default function Layout({ children }: { children: React.ReactNode }) {
after(() => {
// レイアウトがレンダリングされユーザーに送信された後に実行
log()
})
return <>{children}</>
}
import { after } from 'next/server'
// カスタムロギング関数
import { log } from '@/app/utils'
export default function Layout({ children }) {
after(() => {
// レイアウトがレンダリングされユーザーに送信された後に実行
log()
})
return <>{children}</>
}
補足:
after
は動的 API ではなく、呼び出してもルートが動的になることはありません。静的ページ内で使用された場合、コールバックはビルド時またはページが再検証されるたびに実行されます。
リファレンス
パラメータ
- レスポンス(またはプリレンダリング)が完了した後に実行されるコールバック関数。
実行時間
after
は、プラットフォームのデフォルトまたはルートの設定された最大実行時間まで実行されます。プラットフォームがサポートしている場合、maxDuration
ルートセグメント設定を使用してタイムアウト制限を設定できます。
補足事項
after
は、レスポンスが正常に完了しなかった場合でも実行されます。エラーがスローされた場合やnotFound
またはredirect
が呼び出された場合も含まれます。after
内で呼び出される関数の重複を避けるために React のcache
を使用できます。after
は他のafter
呼び出し内にネストできます。例えば、after
呼び出しをラップして追加機能を提供するユーティリティ関数を作成できます。
使用例
リクエスト API との併用
サーバーアクション や ルートハンドラ 内で after
と共に cookies
や headers
などのリクエスト API を使用できます。これは、変更後のアクティビティをログに記録するのに便利です。例:
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
export async function POST(request: Request) {
// 変更を実行
// ...
// 分析のためにユーザーアクティビティを記録
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' },
})
}
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
export async function POST(request) {
// 変更を実行
// ...
// 分析のためにユーザーアクティビティを記録
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>()
// Next.js が使用するアクセサを定義して注入
const RequestContext: NextRequestContext = {
get() {
return RequestContextStorage.getStore()
},
}
globalThis[Symbol.for('@next/request-context')] = RequestContext
const handler = (req, res) => {
const contextValue = { waitUntil: YOUR_WAITUNTIL }
// 値を提供
return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}
バージョン履歴
バージョン履歴 | 説明 |
---|---|
v15.1.0 | after が安定版になりました。 |
v15.0.0-rc | unstable_after が導入されました。 |