Skip to content

React Router v6 で現在のルートパターンを取得する方法

問題点

React Router v6 を使用する際に、現在のルートのパスパターン(例: :state/:city*)をコンポーネント内で取得したい場合があります。ただし、React Router v6 にはこれを直接取得するためのフックが提供されていません。

jsx
<Route
    path=":state/:city*"
    element={
        <Page />
    }
/>
jsx
// Page.jsx
function Page() {
    // 存在しない usePathPattern フック
    const pathPattern = usePathPattern(); // ":state/:city*" を取得したい
    ...
}

解決策

現在のルートパターンを取得するには、複数のアプローチがあります。状況に応じて最適な方法を選択してください。

方法1: matchRoutes を使用する(推奨)

ルート定義の配列がある場合、matchRoutes 関数を使用して現在のロケーションに一致するルートを検索できます。

jsx
import { matchRoutes, useLocation } from "react-router-dom"

// アプリケーションのルート定義
const appRoutes = [
  { path: '/' },
  { path: ':state/:city*' },
  // 他のルート...
]

function useCurrentPathPattern() {
  const location = useLocation()
  const matches = matchRoutes(appRoutes, location)
  
  if (!matches) {
    return location.pathname === '/' ? '/' : '*'
  }
  
  return matches
    .map(({ route }) => route.path)
    .filter(Boolean)
    .join('/')
}

// 使用例
function Page() {
  const pathPattern = useCurrentPathPattern()
  // pathPattern = ":state/:city*"
  return <div>現在のパスパターン: {pathPattern}</div>
}

TIP

この方法は、ルート定義を一元的に管理している場合に最適です。ネストされたルートも正しく処理されます。

方法2: useLocation と useParams を組み合わせる

よりシンプルなアプローチとして、現在のパスからパラメータを抽出してパターンを再構築する方法もあります。

jsx
import { useLocation, useParams } from "react-router-dom"

function usePathPattern() {
  const { pathname } = useLocation()
  const params = useParams()
  
  return Object.keys(params).reduce((path, paramKey) => {
    const paramValue = params[paramKey]
    if (paramValue) {
      return path.replace(`/${paramValue}`, `/:${paramKey}`)
    }
    return path
  }, pathname)
}

注意

この方法は単純なケースでは動作しますが、ネストされたルートや複雑なパラメータがある場合には正しく機能しない可能性があります。

方法3: ルート定義の事前共有

アプリケーションの設計段階でルート定義を共有する方法を考慮することも重要です。

jsx
// routes.js
export const ROUTES = {
  HOME: '/',
  LOCATION: ':state/:city*',
  PROFILE: 'profile/:userId'
}

// App.jsx
import { ROUTES } from './routes'

<Routes>
  <Route path={ROUTES.LOCATION} element={<Page />} />
</Routes>

// Page.jsx
import { ROUTES } from '../routes'

function Page() {
  // ルートパターンを知っている
  const pathPattern = ROUTES.LOCATION
  // ...
}

高度な使用法

ネストされたルートの処理

ネストされたルートを適切に処理するには、より複雑なロジックが必要です。

jsx
import { matchRoutes, useLocation } from "react-router-dom"

const appRoutes = [
  { 
    path: '/',
    children: [
      { path: ':state' },
      { path: ':state/:city*' }
    ]
  }
]

function useNestedPathPattern() {
  const location = useLocation()
  const matches = matchRoutes(appRoutes, location)
  
  if (!matches) return '*'
  
  return matches
    .map(({ route }) => route.path)
    .filter(Boolean)
    .join('/')
    .replaceAll(/\/\*?\//g, '/')
}

パフォーマンス考慮事項

usePathPattern フックを頻繁に使用する場合は、メモ化を検討してください。

jsx
import { useMemo } from 'react'

function useMemoizedPathPattern() {
  const location = useLocation()
  
  return useMemo(() => {
    // 計算コストの高いパターン生成ロジック
    const matches = matchRoutes(appRoutes, location)
    // ...
    return pattern
  }, [location.pathname]) // locationオブジェクト全体ではなくpathnameに依存
}

まとめ

React Router v6 で現在のルートパターンを取得するには、主に以下の方法があります:

  1. matchRoutes を使用 - ルート定義がある場合の最も信頼できる方法
  2. useLocationuseParams を組み合わせ - シンプルなケース向け
  3. ルート定義を事前に共有 - 設計段階で解決する方法

アプリケーションの複雑さと要件に基づいて適切な方法を選択してください。ネストされたルートや動的セグメントを扱う場合は、matchRoutes を使用する方法が最も堅牢です。