はじめに
この記事では、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(フレームワーク利用) 実践ガイド:ブログサイトを作りながら学ぶサーバーサイド、クライアントサイドのレンダリング
React Router v7のフレームワーク機能を使ったブログサイト構築のステップバイステップガイド。JSON Placeholderを活用して投稿データを取得し、トップページにレンダリングする仕組みを詳細に紹介。スピナーの導入や実践的な設定も含めた、実用的なガイドです。
shinagawa-web.com
React Router v7(フレームワーク利用) 実践ガイド:ブログサイトを作りながら学ぶ最新ルーティング
React Router v7のフレームワーク機能を使ったブログサイト構築のステップバイステップガイド。トップページや動的ルーティング、セグメントの実装例を交えて、新しいルーティング機能を活用する方法を解説します。
shinagawa-web.com
React開発を加速するVite入門:高速で柔軟なプロジェクトセットアップガイド
Viteを活用したReactプロジェクトのセットアップ方法を徹底解説!Viteの基本特徴から環境変数の使い方、便利なカスタマイズ方法まで、開発スピードを最大化するヒントをお届けします。
shinagawa-web.com
スキーマ駆動開発の実践:React × Express × GraphQLで効率的なAPI設計を実現
GraphQLを活用したスキーマ駆動開発(Schema-Driven Development, SDD)の実践方法を解説します。React(フロントエンド)とExpress(バックエンド)を組み合わせ、GraphQLスキーマを基にAPI設計を進めることで、型安全性と開発効率を向上させる手法を紹介します。GraphQL Code Generatorを用いた型定義の自動生成、スキーマ設計のベストプラクティス、Turborepoによるモノレポ構成についても詳しく解説します。
shinagawa-web.com
フロントエンドのテスト自動化戦略:Jest・Playwright・MSW を活用したユニット・E2E・API テスト最適化
フロントエンド開発において、品質を担保しながら効率的に開発を進めるためには、適切なテストの自動化が不可欠です。本記事では、Jest や Vitest を活用したユニットテストの導入・強化、React Testing Library や Storybook との統合によるコンポーネントテストの最適化、Playwright / Cypress を用いた E2E テストの拡充について詳しく解説します。さらに、Supertest や MSW を活用した API テストの自動化、Faker / GraphQL Mock によるモックデータの整理、CI/CD パイプラインにおける並列実行やキャッシュ活用による最適化など、テストを効果的に運用するための手法を紹介。また、Codecov / SonarQube によるテストカバレッジの可視化や、フィーチャーフラグを考慮したテスト戦略の策定についても解説し、実践的なアプローチを提案します。テストの信頼性と効率を向上させ、開発プロセスを強化したいフロントエンドエンジニア必見の内容です。
shinagawa-web.com
Webアクセシビリティの完全ガイド:Lighthouse / axe による自動テスト、WCAG基準策定、キーボード操作・スクリーンリーダー対応まで
Webアクセシビリティの課題を解決するための包括的なガイド。Lighthouse / axe を活用した自動テストの設定、WCAGガイドラインに基づく評価基準の整備、キーボード操作やスクリーンリーダー対応の改善、カラーコントラストの最適化、ARIAランドマークの導入、フォームやモーダルの操作性向上まで詳しく解説。定期的なアクセシビリティレポートを活用し、継続的な改善を実現する方法も紹介します。
shinagawa-web.com
チャットアプリ(画像・PDF送信、ビデオ通話機能付き)
お客様固有の要件を除き一般的なチャットアプリに求められる最低限の機能を実装しデモアプリとしてご紹介いたします。
shinagawa-web.com
React × Tailwind CSS × Emotionで実践するコンポーネント設計ガイド:デザインシステム・状態管理・再利用性の最適解
React、Tailwind CSS、Emotion、Storybook、Figma、Next.jsを活用したコンポーネント設計のベストプラクティスを紹介。デザインシステムに基づく命名規則、適切な状態管理、再利用性を高める抽象化、アクセシビリティ対応、スタイルガイドラインの整備、テーマ設定、バージョン管理、ドキュメント作成まで、モダンフロントエンド開発に欠かせない知識を徹底解説します。
shinagawa-web.com
弊社の技術支援サービス
無駄なコストを削減し、投資対効果を最大化する
クラウド費用の高騰、不要なSaaSの乱立、開発工数の増加――これらの課題に悩んでいませんか?本サービスでは、クラウドコストの最適化、開発効率向上、技術選定の最適化 を通じて、単なるコスト削減ではなく、ROIを最大化する最適解 をご提案します。
shinagawa-web.com
最新技術の導入・検証を支援するPoCサービス
Remix、React Server Components、TypeScript移行、クラウドサービス比較、マイクロサービス、サーバーレス、デザインシステムなど、最新技術のPoC(概念実証)を通じて、最適な技術選定と導入を支援します。貴社の開発課題に合わせた検証・実装で、ビジネスの成長を加速させます。
shinagawa-web.com
開発生産性を最大化するための支援サービス
開発チームの生産性向上、コードの品質管理、インフラの最適化まで、様々な側面からサポートします。コードベースのリファクタリングから、テスト自動化、オンボーディング強化まで、プロジェクトの成功に必要なすべての支援を提供。御社の開発現場が効率的に機能するように、技術的な障害を取り除き、スムーズな開発を実現します。
shinagawa-web.com
開発品質向上支援 – 効率的で安定したプロダクトを実現
フロントエンドからバックエンド、データベースまで、開発プロセス全体を最適化し、安定したプロダクト作りをサポートします。コードレビューの仕組み、型定義の強化、E2Eテスト環境の構築など、開発の各ステップにおけるベストプラクティスを導入することで、より効率的でバグの少ない、そしてユーザー満足度の高いサービス提供を支援します。
shinagawa-web.com
Webアプリのセキュリティ強化支援
Webアプリの脆弱性対策からインフラのセキュリティ強化まで、包括的なセキュリティ支援を提供。OWASP Top 10対策、JWT認証の最適化、APIのアクセス制御、依存パッケージの監査、セキュアコーディングの標準化など、実践的なアプローチで開発現場の安全性を向上させます。
shinagawa-web.com
目次
お問い合わせ