React RouterでReactアプリをルーティングする!ルートの階層構造とページ遷移。
この記事では、Reactアプリの定番のReactルーティングのためのライブラリである「ReactRouter」を使った方法を紹介する。
ルーティングは本格的にReactアプリを作成するなら必ず必要となる。
基本的なパターンは使いこなせるようになっておこう!
ルーティングとは?
最初に「ルーティング」について確認しておきたい。
通常、ウェブサイトのURLは「ホームアドレス」と「パス」から構成される。
今、あなたが開いているこのページを例にすると次のようになる。
- URL ➡ https://ugo.tokyo/react-routing
- ホームアドレス ➡ https://ugo.tokyo
- パス ➡ react-routing
ルーティングとはパスにコンポーネントを割り当てる作業だと考えると分かりやすいだろう。
実際にアプリで使用されるルーティングはより複雑で階層構造を持つことが多い。
React Routerについて
React Router公式サイト:: https://reactrouter.com
Reactには様々なルーティングのためのライブラリが存在するが、その中でもっともよく使われている定番のライブラリがこの「React Router」だ。
Microsoft・NETFLIX・Twitterといった大企業で導入されていることからも信頼のおけるライブラリであることが分かるだろう。
現在の最新バージョンはv6となっている。
なお、Reach RouterはReact Routerの姉妹ツールである。
React Routerの使い方
ここでは簡単なオンラインショッピングサイトを作り、ルーティングの基本的な使い方を勉強しよう。
*ここで紹介するサンプルプロジェクトはReact Router公式サイトのチュートリアルをこの記事用にアレンジしたものです。
React Routerをインストールする
React Routerをインストールするために以下のコマンドを実行しよう。
npm install react-router-dom@6
シンプルなページ遷移を試す
まずはシンプルなルーティングから始めてみよう。
メインページにあたるApp.jsに2つのリンクを定義する。
<Link>タブ内のto属性でページのパスを指定する。
<Outlet>タグでページ内容を描画する位置を指定する。
import './App.css';
import { Link, Outlet } from 'react-router-dom';
export default function App() {
return (
<div>
<h1>書籍のオススメ</h1>
<nav
style={{
borderBottom: 'solid 3px gray',
paddingBottom: '25px',
}}
>
<Link to="/book-list">商品一覧</Link> |{' '}
<Link to="/account">マイアカウント</Link>
</nav>
<Outlet />
</div>
);
}
リンク先となる2つのページを作成する。
export default function BookList() {
return (
<main style={{ padding: "1rem 0" }}>
<h2>商品一覧</h2>
</main>
);
}
export default function MyAccount() {
return (
<main style={{ padding: '1rem 0' }}>
<h2>マイアカウント</h2>
</main>
);
}
Routeの構造を定義する
メインページとリンク先の2つのページが出来たらindex.js(もしくはmain.jsx)にてRouteの設定をおこなう。
import { render } from 'react-dom';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import App from './App';
import MyAccount from './routes/MyAccount';
import BookList from './routes/BookList';
const rootElement = document.getElementById('root');
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="account" element={<MyAccount />} />
<Route path="book-list" element={<BookList />} />
</Route>
</Routes>
</BrowserRouter>,
rootElement
);
render関数に<BrowserRouter>、<Routes>、<Route>の順でタグを設定する。
それぞれの<Route>タグのpathにはパスの名称を、elementにはコンポーネントの変数を鍵カッコで囲み指定する。
「/」はアプリのルートをあらわす。
アプリを実行すると以下のような画面が表示されるはずだ。
それぞれのリンクをクリックするとURL内のパスが切り替わるはずなので確認してみてほしい。
ブラウザのURL欄にパスを記述することでコンポーネントを呼び出すこともできるし、ブラウザの戻る・進むボタンをクリックすることでも画面を遷移することができる。
無効なパスのためのルートを指定する
無効なパスを呼び出そうとした時のためのメッセージもindex.jsにて指定しておこう。
//
const rootElement = document.getElementById('root');
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="account" element={<MyAccount />} />
<Route path="book-list" element={<BookList />} />
<Route
path="*"
element={
<main style={{ padding: '1rem' }}>
<p>There's nothing here!</p>
</main>
}
/>
</Route>
</Routes>
</BrowserRouter>,
rootElement
);
本のリストを表示する
次は商品一覧に表示するための本のデータを用意する。
このファイルにはすべての本を取得するための「getBooks」と特定の本を取得するための「getBook(id)」を定義している。
let books = [
{
name: 'React入門',
id: 1,
price: 1580,
},
{
name: 'サルでも分かる!React',
id: 2,
price: 800,
},
{
name: 'Angularで一からWebアプリケーションを作る',
id: 3,
price: 1420,
},
{
name: 'TypeScriptの教科書',
id: 4,
price: 1800,
},
];
export function getBooks() {
return books;
}
export function getBook(id) {
return books.find((book) => book.id === id);
}
取得した本の一覧をBookListコンポーネントで出力する。
import { NavLink, Outlet } from 'react-router-dom';
import { getBooks } from '../data';
export default function BookList() {
let books = getBooks();
return (
<div style={{ display: 'flex' }}>
<nav
style={{
borderRight: 'solid 1px',
padding: '1rem',
}}
>
{books.map((book) => (
<NavLink
style={({ isActive }) => {
return {
display: 'block',
margin: '1rem 0',
color: isActive ? 'red' : '',
};
}}
to={`/book-list/${book.id}`}
key={book.id}
>
{book.name}
</NavLink>
))}
</nav>
<Outlet />
</div>
);
}
本が一覧で表示されたはず。この段階では本のタイトルをクリックすると空白のページが表示される。
パスでパラメーターを渡す
次に本の詳細を表示するためのコンポーネントを作成しよう。
パスにはパラメーターを指定することもできる。本のIDをパラメーターとして使ってどの本の詳細を表示するか指定しよう。
本の詳細を表示するための「BookDetail」ページを作成する。
import { useParams } from 'react-router-dom';
import { getBook } from '../data';
export default function BookDetail() {
let params = useParams();
let book = getBook(parseInt(params.id, 10));
return (
<main style={{ padding: '1rem' }}>
<p>商品番号: {book.id}</p>
<h2>{book.name}</h2>
<p>価格: {book.price}円</p>
</main>
);
}
index.jsのbook-listルートを次のようにアップデートする。
pathに入力されたセミコロン「:」はそのパスがパラメーターであることをあらわす。
<Route path="book-list" element={<BookList />}>
<Route path=":id" element={<BookDetail />} />
</Route>
クリックした本の詳細が右側に表示されればアップデートは完了だ。
動的に特定のパスを開く
最後に動的に特定のパスを開く方法を説明したい。
この場合<Outlet>タグを使用せずにダイレクトにパスを呼び出すことができる。
方法は以下のようにnavigate関数を呼びだすだけだ。
navigate("/book-list");