前回はReact Routerの基本的な機能を利用し簡単な図鑑アプリを作成しました。
今回はリクエストを受けたURLの一部をパラメーターとして受け取ってみます。
例えばブログやTwitterのようなアプリで特定のIDの記事を表示したい場合/posts/view/123
といった形式のURLにアクセスするとします。ここで問題になるのは1000個の記事があった場合、1000個の<Route>
を定義する必要が出てくるのかという点ですね。こういった場合に特定のパターンのURLは一部の文字列をパラメーターとして設定することができます。
目次
名産品図鑑アプリを作る その2
前回と同様に都道府県別に名産品を表示する簡単なWebアプリです。
実行結果は同じですが、コードを大幅に書き換えています。
実行結果
ソースコード
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } 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="/area/1">埼玉県</Link></li>
<li>┗ <Link to="/area/2">島根県</Link></li>
</ul>
{/* ここから下が実際のコンテンツに置き換わる */}
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/index.html" component={Home} />
<Route path="/area/:cd" component={Meisan} />
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
);
}
}
/**
* トップページ
*/
function Home(){
return (
<div className={"item"}>
<h2>名産品図鑑</h2>
<ul>
<li><Link to="/area/1">埼玉県<br /><img src="/image/saitama.png" /></Link></li>
<li><Link to="/area/2">島根県<br /><img src="/image/shimane.png" /></Link></li>
</ul>
</div>
);
}
/**
* 404
*/
function NoMatch(){
return (
<div className={"item"}>
<h2>URLが存在しません</h2>
</div>
);
}
/**
* 名産品Component
*/
class Meisan extends Component{
constructor(props){
super(props);
this.area =[
{
cd: 1,
name: "埼玉県",
img: "/image/saitama.png",
meisan: ["十万石まんじゅう", "深谷ねぎ", "草加せんべい", "いも"]
},
{
cd: 2,
name: "島根県",
img: "/image/shimane.png",
meisan: ["しじみ", "あご野焼", "出雲そば", "ぶどう"]
}
];
}
render(){
let cd = this.props.match.params.cd;
if( (0 < cd) && (cd <= this.area.length) ){
let area = this.area[cd - 1];
let key = 1;
let li = area.meisan.map( val => <li key={key++}>{val}</li> );
return (
<div className={"item"}>
<h2>{area.name}</h2>
<img src={area.img} />
<ul>
{li}
</ul>
</div>
);
}
else{
return (
<div className={"item"}>
<h2>Not Found</h2>
</div>
);
}
}
}
export default App;
App.css
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の一部をパラーメーターとして受け取る
今回のポイントは以下ですね。
<Route path="/area/:cd" component={Meisan} />
他のフレームワークなどでもよく見かける書式ですが、path属性を上記のように記述することで:cd
の部分にどのような文字列が来てもこのルーティング設定が適用されます。またここで:cd
にマッチした値はComponentにpropsとして渡されます。
例えば/area/123
へアクセスがあった場合、Meisan Componentではprops.match.params.cd
を参照することで123
の値を取り出すことができます。
class Meisan extends Component{
constructor(props){
props.match.params.cd;
}
}
複数同時にマッチするのを防ぐ
<Route>
のpath属性の指定方法によっては、複数同時に実行されてしまう可能性があります。
<Route path="/area/1" component={Home} />
<Route path="/area/:cd" component={Meisan} />
これを防ぐためにはReactRouterの<Switch>
を利用します。冒頭のimport
でSwitch
の呼び出しを忘れずに。
<Switch>
<Route path="/area/1" component={Home} />
<Route path="/area/:cd" component={Meisan} />
</Switch>
<Route>
を<Switch>
の中に列挙することで、どれか一つだけが実行されます。上から順番に比較され最初にマッチした物が実行されるようです。逆にグローバルナビなど同時に実行したい物である場合は<Switch>
の外に出しておく必要があります。
いずれにもマッチしない場合のルーティング
どのルーティングにもマッチしない場合は<Route>
のpath属性を指定しないことで、いわゆる404 NotFound
時の処理を定義することができます。
<Switch>
<Route exact path="/" component={Home} />
<Route path="/area/:cd" component={Meisan} />
<Route component={NoMatch}/>
</Switch>
続き
参考ページ
このブログを応援する
お寄せいただいたお気持ちは全額サーバ代や次の記事を執筆するための原資として活用させていただいております。この記事が参考になった場合などぜひご検討ください。
同じカテゴリの記事
- はじめてのReact #30 「CSSフレームワークを導入する」Material-UI テーマをカスタマイズ編
- はじめてのReact #29 「CSSフレームワークを導入する」Material-UI アイコンと文字スタイル編
- はじめてのReact #28 「CSSフレームワークを導入する」Material-UI グリッド編
- はじめてのReact #27 「CSSフレームワークを導入する」Material-UI インストール編
- はじめてのReact #26 「ルーティングに対応する」設定をJSONにまとめる編 react-router@v5
- はじめてのReact #25 「ルーティングに対応する」認証とリダイレクト編 react-router@v5
- はじめてのReact #23 「ルーティングに対応する」基本編 react-router@v5
- はじめてのReact #22「ToDoアプリを作る」 後編