適当おじさんの適当ブログ

技術のことやゲーム開発のことやゲームのことなど自由に雑多に書き連ねます

React RouterでWebアプリのナビゲーションバーを作ったメモ

はじめに

ReactとReact Routerで、以下のようなナビゲーションバーを作成したときのメモです。

f:id:subarunari:20180817140827g:plain

この記事では、はじめにReact Routerの各種コンポーネントの概要について触れています。その後、サンプルコードを掲載しています。サンプルはWebアプリケーションであることを前提としています。React Native については一切触れていません。

使用しているライブラリとバージョンは以下のようになっています。v3以前のReact Routerだと存在しない機能にも触れているので注意してください。

パッケージ名 バージョン
react 16.4.2
react-dom 16.4.2
react-router-dom 4.3.1

React Router

reacttraining.com

ルーティングのための各種機能を提供するライブラリです。ルーティングにより、URLとコンポーネントを対応づけられます。ブラウザ等でURLが指定されると、対応するコンポーネントを表示してくれるようになります。これにより、SPAなアプリケーションの状態を、ブラウザの履歴として保存できるようになります。また、特定のページにURLを指定して直接アクセスできるようになります。React Routerの機能はすべてReactのコンポーネントとして提供されています。

パッケージ

react-router というパッケージが存在しますが、これを直接インストールする必要はありません。代わりに react-router-dom もしくは react-router-native を、自分の開発するアプリケーションに合わせてインストールします。

今回はWebアプリなので、react-router-dom をインストールします。

$ yarn add react-router-dom

Routerコンポーネント

役割に応じたRouterがいくつかあります。まずは、どのRouterを使用するか決める必要があります。Webアプリ向けには、BrowserRouterHashRouter が提供されています。ネイティブアプリであれば、NativeRouter があります。

BrowserRouter と HashRouter は、生成するURLに若干違いがあります。また、BrowserRouterはHTML5の history API をサポートしているブラウザで使用可能です。レガシーなブラウザをサポートしたい場合はHashRouterを利用します。また、公式ドキュメントには静的ファイルだけを提供するような場合も HashRouter が良いと書かれています。

Generally speaking, you should use a <BrowserRouter> if you have a server that responds to requests and a <HashRouter> if you are using a static file server. 公式ドキュメント - Routers

この記事ではひとまず BrowserRouter を使うことにします。

Routeコンポーネント

ルーティングを定義します。以下のように「どのパスでどのコンポーネントをレンダリングするか」をRouteコンポーネントのpropsに指定します。

<BrowserRouter>
  <Route path="/" component={IndexPath} />
  <Route path="/path2" component={Path2} />
</BrowserRouter>

上の例では、URLが / の場合に <IndexPath /> がレンダリングされます。/path2 の場合は、 <IndexPath /> と <Path2 /> の両方がレンダリングされます。これは、前方一致でマッチングするすべてのコンポーネントをレンダリングするためです。したがって、/ で始まるすべてのURLで <IndexPath /> がレンダリングされます。

この振る舞いが便利なこともありますが、困る場合もあります。完全一致した時のみレンダリングさせたい場合は、exact を指定します。これで、/ では <IndexPath /> 、 /path2 では <Path2 /> がレンダリングされるようになります。

<BrowserRouter>
  <Route exact path="/" component={IndexPath} />
  <Route path="/path2" component{Path2} />
</BrowserRouter>

NavLinkコンポーネント

リンクを生成できるコンポーネントには、 LinkNavLink があります。ナビゲーションバーを作るにあたっては、NavLinkのほうが都合がいいです。NavLinkは、「リンクのURLと現在のURLが同じ場合に見た目を変える」ということが簡単に実現できます。下記のように、activeClassNameactiveStyle に値を指定するだけです。

<NavLink to='/test' className='test' style={{fontSize: '1rem'}} activeClassName='active' activeStyle={{color: 'red'}} />

レンダリングされると以下のようになります。className や style が元から指定されている場合は、それに追加される形でレンダリングされます。

<!-- /test にいる場合 -->
<a href="/test" class="test active" style="font-size: 1rem; color: red;" />

<!-- /test 以外にいる場合 -->
<a href="/test" class="test" />

activeClassName や activeStyle はルーティングと同様に前方一致で有効となります。BrowserRouterと同様に exact を指定することで、完全一致のときのみ有効にさせることができます。

自分で頑張って処理を書けば Link でも同じことを実現できますが、少ないコードで書けるのであればそれに越したことはありません。ということで今回は NavLink を使います。

ナビゲーションバーの作成

react-router-domのBrowserRouter, Route, NavLinkの3つのコンポーネントを使って、ナビゲーションバーを作成していきます。ナビゲーションバーのUIを考える際には、以下のページが参考になるので、ぜひ合わせてチェックしてみてください。

ナビゲーションバー用コンポーネントを作る

NavLinkでリンクを作成します。activeClassName でクラスを指定し、該当ページにいるときだけリンクが青くなるようにしています。/ の場合にのみアクティブと判定させるために、1つ目の NavLink に exact を指定しています。

同じクラスを何度も指定するのが少し気持ち悪い感じもします。HeaderLink のようなコンポーネントを作って、NavLinkをラップしておくと少しスッキリするかと思います。

見た目を整える

参考までに、この記事のために作成したscssファイルも掲載しておきます。色々雑ですが、話の本筋ではないのでどうかご勘弁を・・・。

ページ用コンポーネントを作る

続いて、各リンクに対応するコンポーネントを作成しておきます。

画面遷移に成功していることだけわかればいいので、自分が何者かを表示するだけのシンプルなコンポーネントとなっています。これらはあとで、Routeコンポーネントのcomponentパラメータに指定します。

ルーティング

Routeコンポーネントで、URLとページ用コンポーネントを対応づけます。RouteにもNavLinkと同様に exact を指定している箇所があります。exact を指定しない場合、/item1/item2 で Homeコンポーネントが表示されてしまうためです。

最後に、作成したコンポーネントを ReactDOM.render でレンダリングすればページ冒頭のようなナビゲーションバーが表示されるはずです。

参考