はじめに
この記事では、React Router v7を使用してブログサイトを構築する方法を紹介します。React Routerは、Reactアプリケーションのルーティングを簡単かつ柔軟に設定できるライブラリで、ブログサイトのような多ページのアプリケーションに最適です。この記事を通じて、動的なページ遷移やネストされたルート、個別記事ページの設定など、React Router v7の基本的な使い方を学ぶことができます。
React Router v7の新機能を活かし、スムーズで直感的なナビゲーションを実現するための実践的なテクニックも紹介しますので、ぜひ最後まで読んで、あなたのReactアプリに役立ててください。
React Router とは
React Routerは、Reactアプリケーション向けのルーティングライブラリです。ルーティングとは、ユーザーが特定のURLにアクセスした際に、どのコンポーネントを表示するかを制御する仕組みのことです。
主な特徴
-
宣言的なルーティング
React Routerでは、JSXを使用してルートを定義するため、直感的で可読性が高いコードが書けます。 -
ダイナミックなルート
動的セグメントやオプションセグメントを使って、ユーザーのリクエストに応じたページを柔軟に表示できます。 -
ネストされたルート
子ルートを親ルートの中に定義することで、複雑なUIの設計をシンプルに行えます。 -
レイアウトルート
再利用可能なレイアウトを定義し、ページ間で共通するUIを効率的に管理できます。 -
スプラット(ワイルドカード)
パスに一致しない部分をキャッチして処理するルート設定が可能です。 -
Reactの最新機能に対応
React Router v7は、Reactの最新バージョンをサポートし、Suspenseやコンポーネントの遅延読み込みとも連携できます。
なぜ使うのか?
- **SPA(シングルページアプリケーション)**を構築する際に不可欠。ページ遷移時にページ全体をリロードせず、コンポーネントの切り替えでスムーズな操作感を提供。
- 大規模アプリケーションでも、ルート管理が簡単かつ拡張性が高い。
- URL構造が明確になり、SEOやアクセシビリティの向上にも寄与。
どんな場面で役立つ?
- ブログやECサイトのように、複数のページやカテゴリを管理する場合。
- ダッシュボードのように、ページごとに異なるレイアウトを持つ場合。
- 動的なページ生成が必要な場合(例: /users/:id のようなパス)。
ライブラリ利用とは?
React Routerはv7よりReactフレームワークとして最大限に使用することも、独自のアーキテクチャを持つライブラリとして最小限に使用することもできます。
これまでのバージョン(v6)以前のバージョンはシンプルで宣言的なルーティング・ライブラリとして使用することができます。
URLとコンポーネントのセットをマッチングして、URLデータへのアクセスを提供し、アプリ内をナビゲートすることとなります。
これまでv6を利用してきたユーザーはバージョンアップしたのち引き続きライブラリとしてReact Routerを使うことが多いかと思います。
今回この記事でご紹介する機能についてはこちらのライブラリ利用によるものとなります。
ルーティング制御をメインとしていますがブログサイトを構築する上で欠かせない機能を多数提供しています。
フレームワーク利用とは?
React Routerはv7よりReactフレームワークとして活用することも可能となりました。
具体的には下記のような機能を提供しています。
- Vite バンドラーと開発サーバーの統合
- ホットモジュールの置換
- コード分割
- 型の安全性を確保したファイルシステムまたは設定ベースのルーティング
- 型の安全性を確保したデータロード
- 型の安全性を確保したアクション
- アクション後のページデータの自動再バリデーション
- SSR、SPA、静的レンダリング戦略
- 保留状態と楽観的 UI
- デプロイメントアダプター
セットアップ
今回はViteを使ってReactを起動しそこにReact Router v7を設定していきます。
mkdir react-router-v7-tutorial
cd react-router-v7-tutorial
npx create-vite@latest .
今回は下記を選択しました。
- Select a framework:
React
- Select a variant:
TypeScript + SWC
下記コマンドでReactを起動してみます。
npm install
npm run dev
http://localhost:5173/
でアクセスできたらセットアップ完了です。
viteに関する基礎的な内容を網羅した記事もあります。
合わせてご参照ください。
React Router v7のインストール
下記コマンドでReact Router v7
のインストールを行います。
npm i react-router
src/main.tsx
ファイルで、アプリケーションを <BrowserRouter> で囲んでレンダリングします。
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
- import './index.css'
+ import { BrowserRouter } from "react-router";
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
+ <BrowserRouter>
<App />
+ </BrowserRouter>
</StrictMode>,
)
以上でReact Router v7
が使用できるようになりました。
cssを削除したのでトップページのデザインが若干変化しましたが気にしなくて大丈夫です。
ルーティング
今回はブログサイトを構築する想定でサイトを構築しつつReact Router v7
のルーティング機能をご紹介していきます。
ルートの設定
/
をブログのトップページとして記事の一覧を表示してみようと思います。
まずはブログ記事一覧を作成します。
データベースやWordPressなどのバックエンドツールを用意するのは大変なので下記でブログ記事一覧とします。
export const posts = [
{ id: 1, title: 'React Router 7のセットアップ' },
{ id: 2, title: 'Reactでの状態管理方法' },
{ id: 3, title: 'コンポーネント設計のベストプラクティス' },
]
この一覧を読み込む画面を作成します。
import { posts } from "../const/posts"
function Home () {
return (
<div>
<h1>ホーム</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
{post.title}
</li>
))}
</ul>
</div>
)
}
export default Home
ここまで設定できましたらルートの設定を行います。
import { Routes, Route } from 'react-router'
import Home from './pages/Home'
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
</Routes>
);
}
export default App
見て頂くとなんとなくイメージできるかと思いますが、「/
にアクセスが来た場合にHome
コンポーネントを表示させる」という設定になります。
http://localhost:5173/
にアクセスするとブログ一覧が表示されます。
動的セグメントとルートパラメータ
次はブログの個別記事を参照するための設定をしていきたいと思います。
ホームでブログ記事のタイトルをクリックするとブログの個別記事のページに遷移するというものです。
ブログ一覧にdescription
を追加しました。
また、idを指定すると対象のブログ情報を取得できる関数getPostById
も合わせて作成しました。
export const posts = [
{ id: 1, title: 'React Router 7のセットアップ', description: 'セットアップ以外にも様々な機能をご紹介' },
{ id: 2, title: 'Reactでの状態管理方法', description: 'useState、useContextなどをご紹介' },
{ id: 3, title: 'コンポーネント設計のベストプラクティス', description: 'ディレクトリ構成についてもご紹介' },
]
export const getPostById = (id: number) => {
return posts.find(post => post.id === id);
}
次にブログの個別記事を表示するPost
コンポーネントを作成します。
import { useParams } from 'react-router';
import { getPostById } from '../const/posts';
function Post () {
const { id } = useParams()
const post = getPostById(Number(id))
if (!post) {
return (
<div>
投稿が見つかりませんでした。
</div>
)
}
return (
<div>
<h1>{post.title}</h1>
{post.description}
</div>
);
};
export default Post;
コードに関する詳細を説明します。
import { useParams } from 'react-router';
const { id } = useParams()
こちらはルートパラメータと言ってURLに含まれている値を取得することができます。
このid
は下記のような設定で取得できます。
<Route path="/post/:id" element={<Post />} />
:id
と設定することでid
として取得可能となります。
例えばhttp://localhost:5173/post/1
というURLの場合でアクセスするとid = 1
となります。
const post = getPostById(Number(id))
次に先ほど作成した関数を使ってブログ詳細情報を取得します。
if (!post) {
return (
<div>
投稿が見つかりませんでした。
</div>
)
}
return (
<div>
<h1>{post.title}</h1>
{post.description}
</div>
);
最後に取得したブログ情報を表示させます。
なお存在しないidでアクセスがあった場合にブログ個別記事を表示できなくなりますのでその場合を考慮したレンダリングも合わせて作成します。
以上でブログの個別記事を表示するPost
コンポーネントの作成は完了です。
次にルートの設定を行います。
import { Routes, Route } from 'react-router'
import Home from './pages/Home'
+ import Post from './pages/Post';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
+ <Route path="/post/:id" element={<Post />} />
</Routes>
);
}
export default App
先ほどのルートパラメータで紹介した設定を行います。
これでhttp://localhost:5173/post/1
という形式でブログの個別記事を表示できるようになりました。
最後にブログ一覧から遷移できる設定を行います。
import { posts } from "../const/posts"
+ import { Link } from "react-router"
function Home () {
return (
<div>
<h1>ホーム</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
- {post.title}
+ <Link to={`/post/${post.id}`}>{post.title}</Link>
</li>
))}
</ul>
</div>
)
}
export default Home
React Router
のLink
を使用するとクリックした時にto
で設定したURLに遷移できます。
一通り設定が完了しましたので実際にホーム画面から遷移できるか確認してみます。
ホームで表示されているブログのタイトルをクリックするとブログの個別記事が表示されます。
その後に存在しないブログIDで強制的にアクセスしてみます。
すると「投稿が見つかりませんでした。」というメッセージが表示されます。
ナビゲーション
useNavigate
というフックを使用するとユーザーの操作なしにページ遷移を行うことが可能です。
先ほど存在しないブログIDで強制的にアクセスした場合に「投稿が見つかりませんでした。」というメッセージを表示しました。
こちらそのままだと利用者にとって利便性が低くなりますのでトップページに強制的に戻してあげましょう。
- import { useParams } from 'react-router';
+ import { useParams, useNavigate } from 'react-router';
import { getPostById } from '../const/posts';
function Post () {
const { id } = useParams()
+ const navigate = useNavigate()
const post = getPostById(Number(id))
if (!post) {
+ setTimeout(() => {
+ navigate('/')
+ }, 3000)
return (
<div>
- 投稿が見つかりませんでした。
+ 投稿が見つかりませんでした。トップページに戻ります...
</div>
)
}
return (
<div>
<h1>{post.title}</h1>
{post.description}
</div>
);
};
export default Post;
存在しないブログIDでアクセスした場合の処理としてnavigate('/')
トップに遷移するコマンドを3秒後に実行するよう設定しました。
3秒間だけ表示がありその後自動的にトップに戻ることが可能となります。
ネストしたルートとレイアウト
今度はブログサイトにマイページ画面を作成しようと思います。
マイページではアカウント情報を見る画面と設定変更をできる画面を作成します。
まずは2つの画面を作成します。
タイトルだけの簡単な画面です。(ここがこのブログのメインではないので)
const Account = () => {
return <h2>アカウント</h2>
}
export default Account
const Settings = () => {
return <h2>設定画面</h2>
}
export default Settings
次に作成した画面のルーティングを設定します。
<Route>をネストした構成になっています。
このように設定すると下記のURLでアクセス可能となります。
アカウント画面: http://localhost:5173/mypage/account
設定画面: http://localhost:5173/mypage/settings
実際にアクセスするとそれぞれの画面が表示できるかと思います。
レイアウト
2つの画面はマイページという1つの枠の中で動く画面となります。
ヘッダー要素を作成し画面を切り替えられるよう実装していきたいと思います。
そのために共通のレイアウトになるコンポーネントをまずは作成します。
import { Outlet } from "react-router";
function MyPageLayout() {
const containerStyle: React.CSSProperties = {
backgroundColor: "#f0f0f0",
padding: "20px",
minHeight: "100vh",
}
return (
<div style={containerStyle}>
<h1>マイページ</h1>
<Outlet />
</div>
);
}
export default MyPageLayout
Outlet は、React Router のコンポーネントで、ネストされたルートのコンテンツを表示するためのプレースホルダー です。
具体的には、親ルート に共通のレイアウトやコンポーネント (例: ヘッダーやサイドバー) を定義しつつ、その中に 子ルート のコンテンツを埋め込むために使用されます。
今回はヘッダー部分に「マイページ」を表示し背景をグレーにしました。
import { Routes, Route } from 'react-router'
import Home from './pages/Home'
import Post from './pages/Post';
import Account from './pages/Account';
import Settings from './pages/Settings';
+ import MyPageLayout from './pages/MyPageLayout';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/post/:id" element={<Post />} />
- <Route path="/mypage">
+ <Route path="/mypage" element={<MyPageLayout />}>
<Route path="account" element={<Account />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
export default App
ネストしたルートの親ルートに共通のレイアウトを設定します。
この状態で再度下記URLでアクセスします。
アカウント画面: http://localhost:5173/mypage/account
設定画面: http://localhost:5173/mypage/settings
実際にアクセスするとどちらにもヘッダーと背景のグレーが表示できるかと思います。
ナビゲーション
先ほどまではアカウント画面、設定画面にアクセスする際にURLで直接遷移していましたが、画面から遷移できるよう設定していきます。
まずはナビゲーションを作成します。
import { NavLink } from "react-router";
import './styles.css';
export function MyPageNavigation() {
return (
<nav>
<NavLink to="/" end>ホーム</NavLink>
<NavLink to="/mypage/settings">設定画面</NavLink>
<NavLink to="/mypage/account">アカウント</NavLink>
</nav>
);
}
NavLink
はアクティブ状態をレンダリングする必要があるナビゲーションリンク用です。
具体的には該当のURLにアクセスがしているときにactive
というクラスが設定されます。
そのためCSSでactive
に対して文字色を変えたり背景色を付けたりできるようになります。
nav {
display: flex;
gap: 16px;
}
a.active {
color: red;
}
今回はactive
に対して文字色を赤に設定しました。
ナビゲーションが作成できましたのでこれを画面やレイアウトに適用していきます。
まずはマイページのレイアウトに適用します。
import { Outlet } from "react-router";
+ import { MyPageNavigation } from "./MyPageNavigation";
function MyPageLayout() {
const containerStyle: React.CSSProperties = {
backgroundColor: "#f0f0f0",
padding: "20px",
minHeight: "100vh",
}
return (
<div style={containerStyle}>
- <h1>マイページ</h1>
+ <MyPageNavigation />
<Outlet />
</div>
);
}
export default MyPageLayout
先ほどヘッダーに「マイページ」と表示していた箇所をナビゲーションに置き換えました。
次にホーム画面にもナビゲーションを設定します。
import { posts } from "../const/posts"
import { Link } from "react-router"
+ import { MyPageNavigation } from "./MyPageNavigation"
function Home () {
return (
<div>
- <h1>ホーム</h1>
+ <MyPageNavigation />
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link to={`/post/${post.id}`}>{post.title}</Link>
</li>
))}
</ul>
</div>
)
}
export default Home
以上で設定完了です。
実際にアクセスして確認してみます。
ホーム画面にアクセスするとナビゲーションが表示されます。
また「ホーム」が赤で強調されており現在いる場所が分かりやすくなりました。
次に設定画面にアクセスします。
今度は「設定画面」の文字色が赤になります。
またマイページ用のレイアウトなので背景がグレーになっています。
「アカウント」にアクセスした場合も同様です。
さいごに
この記事では、React Router v7を使用してブログサイトのルーティングを構築する方法を学びました。動的なURLパラメータの取り扱いや、ネストされたルートの設定方法について理解が深まったことと思います。
React Router v7の柔軟性を活かし、あなたのアプリケーションに最適なルーティング設計を行い、ユーザーに快適な体験を提供することができるでしょう。これを基にさらに複雑なルーティングの実装や、パフォーマンスの最適化などにも挑戦してみてください。
ご覧いただきありがとうございました。
関連する技術ブログ
React Router v7(フレームワーク利用) 実践ガイド:ブログサイトを作りながら学ぶサーバーサイド、クライアントサイドのレンダリング
2025/01/23React Router v7(フレームワーク利用) 実践ガイド:ブログサイトを作りながら学ぶ最新ルーティング
2025/01/23React開発を加速するVite入門:高速で柔軟なプロジェクトセットアップガイド
2025/01/17Mock Service Worker (MSW) を使ったAPIモックとテストの効率化
2023/09/25Next.jsとAuth.jsで認証機能を実装するチュートリアル
2024/09/13Next.jsでのメール認証処理の実装ガイド:アカウント登録からトークン検証まで
2024/05/10Next.jsでのメール認証処理の実装ガイド:トークン検証からログイン画面へのリダイレクト処理までの詳細解説
2024/05/13Next.jsを活用したGitHubとGoogleのOAuth認証実装完全ガイド — スムーズなユーザーログインの実現方法
2024/06/11