React Router v6 で現在のルートパターンを取得する方法
問題点
React Router v6 を使用する際に、現在のルートのパスパターン(例: :state/:city*
)をコンポーネント内で取得したい場合があります。ただし、React Router v6 にはこれを直接取得するためのフックが提供されていません。
<Route
path=":state/:city*"
element={
<Page />
}
/>
// Page.jsx
function Page() {
// 存在しない usePathPattern フック
const pathPattern = usePathPattern(); // ":state/:city*" を取得したい
...
}
解決策
現在のルートパターンを取得するには、複数のアプローチがあります。状況に応じて最適な方法を選択してください。
方法1: matchRoutes を使用する(推奨)
ルート定義の配列がある場合、matchRoutes
関数を使用して現在のロケーションに一致するルートを検索できます。
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 を組み合わせる
よりシンプルなアプローチとして、現在のパスからパラメータを抽出してパターンを再構築する方法もあります。
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: ルート定義の事前共有
アプリケーションの設計段階でルート定義を共有する方法を考慮することも重要です。
// 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
// ...
}
高度な使用法
ネストされたルートの処理
ネストされたルートを適切に処理するには、より複雑なロジックが必要です。
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
フックを頻繁に使用する場合は、メモ化を検討してください。
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 で現在のルートパターンを取得するには、主に以下の方法があります:
matchRoutes
を使用 - ルート定義がある場合の最も信頼できる方法useLocation
とuseParams
を組み合わせ - シンプルなケース向け- ルート定義を事前に共有 - 設計段階で解決する方法
アプリケーションの複雑さと要件に基づいて適切な方法を選択してください。ネストされたルートや動的セグメントを扱う場合は、matchRoutes
を使用する方法が最も堅牢です。