React Router v7(ライブラリ利用)を使ったブログサイトの構築ガイド

2025/01/20に公開

はじめに

この記事では、React Router v7を使用してブログサイトを構築する方法を紹介します。React Routerは、Reactアプリケーションのルーティングを簡単かつ柔軟に設定できるライブラリで、ブログサイトのような多ページのアプリケーションに最適です。この記事を通じて、動的なページ遷移やネストされたルート、個別記事ページの設定など、React Router v7の基本的な使い方を学ぶことができます。

React Router v7の新機能を活かし、スムーズで直感的なナビゲーションを実現するための実践的なテクニックも紹介しますので、ぜひ最後まで読んで、あなたのReactアプリに役立ててください。

React Router とは

React Routerは、Reactアプリケーション向けのルーティングライブラリです。ルーティングとは、ユーザーが特定のURLにアクセスした際に、どのコンポーネントを表示するかを制御する仕組みのことです。

https://reactrouter.com/home

主な特徴

  • 宣言的なルーティング
    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

Image from Gyazo

下記コマンドでReactを起動してみます。

npm install
npm run dev

http://localhost:5173/でアクセスできたらセットアップ完了です。

Image from Gyazo

viteに関する基礎的な内容を網羅した記事もあります。

合わせてご参照ください。

https://shinagawa-web.com/blogs/react-vite-setup-guide-for-fast-development

React Router v7のインストール

下記コマンドでReact Router v7のインストールを行います。

npm i react-router

src/main.tsxファイルで、アプリケーションを <BrowserRouter> で囲んでレンダリングします。

src/main.tsx
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を削除したのでトップページのデザインが若干変化しましたが気にしなくて大丈夫です。

Image from Gyazo

ルーティング

今回はブログサイトを構築する想定でサイトを構築しつつReact Router v7のルーティング機能をご紹介していきます。

ルートの設定

/をブログのトップページとして記事の一覧を表示してみようと思います。

まずはブログ記事一覧を作成します。
データベースやWordPressなどのバックエンドツールを用意するのは大変なので下記でブログ記事一覧とします。

src/const/posts.ts
export const posts = [
  { id: 1, title: 'React Router 7のセットアップ' },
  { id: 2, title: 'Reactでの状態管理方法' },
  { id: 3, title: 'コンポーネント設計のベストプラクティス' },
]

この一覧を読み込む画面を作成します。

src/pages/Home.tsx
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

ここまで設定できましたらルートの設定を行います。

src/App.tsx
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/にアクセスするとブログ一覧が表示されます。

Image from Gyazo

動的セグメントとルートパラメータ

次はブログの個別記事を参照するための設定をしていきたいと思います。

ホームでブログ記事のタイトルをクリックするとブログの個別記事のページに遷移するというものです。

ブログ一覧にdescriptionを追加しました。

また、idを指定すると対象のブログ情報を取得できる関数getPostByIdも合わせて作成しました。

src/const/posts.ts
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コンポーネントを作成します。

src/pages/Post.tsx
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コンポーネントの作成は完了です。

次にルートの設定を行います。

src/App.tsx
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という形式でブログの個別記事を表示できるようになりました。

最後にブログ一覧から遷移できる設定を行います。

src/page/Home.tsx
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 RouterLinkを使用するとクリックした時にtoで設定したURLに遷移できます。

一通り設定が完了しましたので実際にホーム画面から遷移できるか確認してみます。

ホームで表示されているブログのタイトルをクリックするとブログの個別記事が表示されます。

その後に存在しないブログIDで強制的にアクセスしてみます。

すると「投稿が見つかりませんでした。」というメッセージが表示されます。

Image from Gyazo

ナビゲーション

useNavigateというフックを使用するとユーザーの操作なしにページ遷移を行うことが可能です。

先ほど存在しないブログIDで強制的にアクセスした場合に「投稿が見つかりませんでした。」というメッセージを表示しました。

こちらそのままだと利用者にとって利便性が低くなりますのでトップページに強制的に戻してあげましょう。

src/page/Post.tsx
- 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つの画面を作成します。
タイトルだけの簡単な画面です。(ここがこのブログのメインではないので)

src/pages/Account.tsx
const Account = () => {
  return <h2>アカウント</h2>
}

export default Account
src/pages/Settings.tsx
const Settings = () => {
  return <h2>設定画面</h2>
}

export default Settings

次に作成した画面のルーティングを設定します。

<Route>をネストした構成になっています。

このように設定すると下記のURLでアクセス可能となります。

アカウント画面: http://localhost:5173/mypage/account
設定画面: http://localhost:5173/mypage/settings

実際にアクセスするとそれぞれの画面が表示できるかと思います。

Image from Gyazo

Image from Gyazo

レイアウト

2つの画面はマイページという1つの枠の中で動く画面となります。

ヘッダー要素を作成し画面を切り替えられるよう実装していきたいと思います。

そのために共通のレイアウトになるコンポーネントをまずは作成します。

src/pages/MyPageLayout.tsx
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 のコンポーネントで、ネストされたルートのコンテンツを表示するためのプレースホルダー です。

具体的には、親ルート に共通のレイアウトやコンポーネント (例: ヘッダーやサイドバー) を定義しつつ、その中に 子ルート のコンテンツを埋め込むために使用されます。

今回はヘッダー部分に「マイページ」を表示し背景をグレーにしました。

App.tsx
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

実際にアクセスするとどちらにもヘッダーと背景のグレーが表示できるかと思います。

Image from Gyazo

Image from Gyazo

ナビゲーション

先ほどまではアカウント画面、設定画面にアクセスする際にURLで直接遷移していましたが、画面から遷移できるよう設定していきます。

まずはナビゲーションを作成します。

src/pages/MyPageNavigation.tsx
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に対して文字色を変えたり背景色を付けたりできるようになります。

src/pages/styles.css
nav {
  display: flex;
  gap: 16px;
}

a.active {
  color: red;
}

今回はactiveに対して文字色を赤に設定しました。

ナビゲーションが作成できましたのでこれを画面やレイアウトに適用していきます。

まずはマイページのレイアウトに適用します。

src/pages/MyPageLayout.tsx
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

先ほどヘッダーに「マイページ」と表示していた箇所をナビゲーションに置き換えました。

次にホーム画面にもナビゲーションを設定します。

Home.tsx
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

以上で設定完了です。

実際にアクセスして確認してみます。

ホーム画面にアクセスするとナビゲーションが表示されます。

また「ホーム」が赤で強調されており現在いる場所が分かりやすくなりました。

Image from Gyazo

次に設定画面にアクセスします。

今度は「設定画面」の文字色が赤になります。

またマイページ用のレイアウトなので背景がグレーになっています。

Image from Gyazo

「アカウント」にアクセスした場合も同様です。

Image from Gyazo

さいごに

この記事では、React Router v7を使用してブログサイトのルーティングを構築する方法を学びました。動的なURLパラメータの取り扱いや、ネストされたルートの設定方法について理解が深まったことと思います。

React Router v7の柔軟性を活かし、あなたのアプリケーションに最適なルーティング設計を行い、ユーザーに快適な体験を提供することができるでしょう。これを基にさらに複雑なルーティングの実装や、パフォーマンスの最適化などにも挑戦してみてください。

ご覧いただきありがとうございました。

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ

関連する弊社の支援サービス