Skip to content

Next.js 13 サーバーコンポーネントでURLパス名を取得する方法

問題点

Next.js 13のApp Router(appディレクトリ)を使用するサーバーコンポーネントで、window.locationを使ってパス名(pathname)を取得しようとしても機能しません。サーバーコンポーネントはブラウザ環境ではないため、windowオブジェクトやlocationオブジェクトにアクセスできないためです。

サーバーコンポーネントの制約

サーバーコンポーネントはサーバー上でレンダリングされるため、ブラウザ関連のAPIや状態(URLパラメーター、HTTPヘッダー、クエリ文字列等)に直接アクセスできません。

推奨解決策: ミドルウェアを利用したカスタムヘッダー

最も信頼性が高く、Vercルチームにも推奨される方法は、ミドルウェアを活用してURL情報をカスタムヘッダーに保存する方法です。

ステップ 1: ミドルウェアの設定

プロジェクトルート(またはsrcディレクトリ内)にmiddleware.tsファイルを作成します:

ts
import { NextResponse } from 'next/server';

export function middleware(request: Request) {
  const url = new URL(request.url);
  
  const requestHeaders = new Headers(request.headers);
  // URL情報をカスタムヘッダーに保存
  requestHeaders.set('x-url', request.url);
  requestHeaders.set('x-origin', url.origin);
  requestHeaders.set('x-pathname', url.pathname);

  return NextResponse.next({
    request: {
      headers: requestHeaders
    }
  });
}

ステップ 2: サーバーコンポーネントでの情報取得

サーバーコンポーネント内でheaders関数を使用し、カスタムヘッダーから情報を取得します:

tsx
import { headers } from 'next/headers';

export default function Page() {
  const headersList = headers();
  
  const headerUrl = headersList.get('x-url') ?? '';
  const pathname = headersList.get('x-pathname') ?? '';
  const origin = headersList.get('x-origin') ?? '';

  console.log('現在のパス名:', pathname);
  
  // コンポーネントのレンダリング処理...
}

パフォーマンスと制限に関する注意点

重要な考慮事項

headers()関数の使用は動的レンダリングを引き起こします。つまり、Next.jsはリクエスト時に毎回サーバーサイドでコンポーネントをレンダリングします。

ts
// headers()を使う → 動的レンダリング
const headersList = headers();
// cookies()を使う → 動的レンダリング
const cookiesList = cookies();

静的なページのパフォーマンスを最適化する必要がある場合は、このアプローチを慎重に検討してください。

代替アプローチ: 組み込みヘッダーを利用する (非推奨)

一部のQ&Aで以下の方法が提案されていましたが、推奨されません:

ts
const pathname = headers().get('next-url'); // 非推奨!

なぜ推奨されないか

  1. next-urlヘッダーはNext.jsの内部使用用であり、突然変更される可能性があります
  2. Vercelのプロダクト責任者が公式に使用を控えるよう推奨
  3. 予測不可能な動作や将来のバージョンで動作しなくなるリスク

クライアントコンポーネントで使用する場合

サーバーコンポーネントでなくクライアントサイドでパス名を取得する必要がある場合:

tsx
'use client';

import { usePathname } from 'next/navigation';

export default function ClientComponent() {
  const pathname = usePathname();
  
  return <div>現在のパス: {pathname}</div>;
}

ベストプラクティスのまとめ

ユースケース推奨アプローチ
サーバーコンポーネントカスタムヘッダーを設定したミドルウェア
クライアントコンポーネントusePathnameフックの使用
静的ページの最適化URL情報が必須か再検討

ミドルウェアを使用するアプローチは、Next.jsの開発チーム推奨の方法ではありませんが、2024年現在、サーバーコンポーネントでURL情報を確実に取得する唯一の安定した手法です。将来的に公式APIが提供される可能性がありますが、現在の実装で実現可能です。