はじめてのReact #23 「ルーティングに対応する」基本編 react-router@v5

React Routerは雑に言うとリクエストされたURLのパスと、ReactのComponentを紐付けてくれる便利なモジュールです。

例えば /foo にアクセスされたら FooComponentを、/barにアクセスされたらBarComponentを実行することができるようになります。 reacttraining.com

今回は3月21日に登場したばかりのReact Router v5を触ってみます。本来はv4.4として出す予定だったそうですがReact 16との互換性が大きく改善されたとのことでメジャーバージョンアップの運びとなったとのこと。使い方もv4系とあまり変わらないようですね。

名産品図鑑アプリを作る

都道府県別に名産品を表示する簡単なWebアプリを作ってみます。内容としては公式サイトのサンプルの見た目をいじっただけの物です。

実行結果

以下から実際に動かせます。面倒だったので埼玉と島根だけですがw s3-us-west-2.amazonaws.com

Reactプロジェクトの準備

create-react-appコマンドでReactの新規プロジェクトを作成します。セットアップ方法など詳しくは過去の記事を参照ください。

$ create-react-app picbook

その後、Webサイト向けのreact-routerモジュールを追加します。

$ cd picbook
$ npm install react-router-dom

ソースコード

App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './App.css';

class App extends Component {
  render() {
    return (
      <Router>
        <div className={"container"}>
          {/* ナビゲーション */}
          <ul className={"gnavi"}>
            <li><Link to="/">名産品図鑑</Link></li>
            <li>┣ <Link to="/saitama">埼玉県</Link></li>
            <li>┗ <Link to="/shimane">島根県</Link></li>
          </ul>

          {/* ここから下が実際のコンテンツに置き換わる */}
          <Route exact path="/" component={Home} />
          <Route path="/saitama" component={Saitama} />
          <Route path="/shimane" component={Shimane} />
        </div>
      </Router>
    );
  }
}

/**
 * トップページ
 */
function Home() {
  return (
    <div className={"item"}>
      <h2>名産品図鑑</h2>
      <ul>
        <li><Link to="/saitama">埼玉県<br /><img src="/image/saitama.png" /></Link></li>
        <li><Link to="/shimane">島根県<br /><img src="/image/shimane.png" /></Link></li>
      </ul>
    </div>
  );
}

/**
 * 埼玉県
 */
function Saitama() {
  return (
    <div className={"item"}>
      <h2>埼玉県の名産品</h2>
      <img src="/image/saitama.png" />
      <ol>
        <li>十万石まんじゅう</li>
        <li>深谷ねぎ</li>
        <li>草加せんべい</li>
        <li>いも</li>
      </ol>
    </div>
  );
}

/**
 * 島根県
 */
function Shimane() {
  return (
    <div className={"item"}>
      <h2>島根県の名産品</h2>
      <img src="/image/shimane.png" />
      <ol>
        <li>しじみ</li>
        <li>あご野焼</li>
        <li>出雲そば</li>
        <li>ぶどう</li>
      </ol>
    </div>
  );
}

export default App;

App.css

a:hover{
  color: red;
}
ul{
  list-style: none;
}

.container{
  display: inline-flex;  /* 横に並べる */
}
.gnavi{
  order: 1;
  width: 80px;
  height: 500px;
  padding: 10px;
  margin-right: 10px;
  background-color: skyblue;
}
.item{
  order: 2;
}

解説

ルーティングの設定

余計な部分はカットしていますが、以下の箇所でURLとComponentの関連付けを行っています。

<Router>
  <Route exact path="/" component={Home} />
  <Route path="/saitama" component={Saitama} />
  <Route path="/shimane" component={Shimane} />
</Router>

/saitamaにアクセスすれば、このコードで言えばfunction Saitama(){}が実行され、実行結果がを書いた場所に表示されます。

exact属性はlocation.pathnameと完全にマッチした場合にのみ実行されます。 例えば /foo#hogeのようにアンカーの指定があったり、/bar?a=1といったクエリーが付いている場合は実行されません。

SPA的に移動する

このアプリ内で埼玉県のページを表示するには 埼玉県 といったようにAタグを書いても移動はできますが、ページ全体を書き換えることになってしまいます。せっかくReactを利用しているのですから、SPA的に最小限の書き換えで済ませたいところ。

そんなときに利用するのがReactRouterから提供されているタグです。

<Link to="/saitama">埼玉県</Link>

これだけで/saitamaのルーティングが別の箇所で定義されていればSPA的な挙動になります。

またテキストだけではなくなどで画像を対象とすることも可能です。

<Link to="/shimane">島根県<br /><img src="/image/shimane.png" /></Link>

ベースのパスを指定したい

basename属性を指定すると、HTMLで言うのような効果になります。

<Router basename="/public/">
<Link to="/saitama">埼玉県</Link>

この場合は最終的に埼玉県とレンダリングされます。ドキュメントルート直下ではなく、何らかのディレクトリの下に置きたい場合などはこちらのオプションを利用することで解決できます。

続き

blog.katsubemakito.net

参考ページ