前々回では基本的なReactRouterの使い方を、前回でURLの一部をパラメーターとして受け取ってみました。
今回はユーザーの状態に合わせてページの出し分けを行います。
具体的には
- 認証済みのユーザーにだけページを表示
- 未認証のユーザーにはログインページを表示
という仕様になります。
名産品図鑑アプリを作る その3
実行結果
謎の地域「?????」をクリックすると認証ページへリダイレクトさせられます。ここでログインボタンをクリックすると、ログイン状態になるので再度「?????」をクリックすると内容が表示されます。
ソースコード
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch, Redirect } 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>
<li>┗ <Link to="/private">?????</Link></li>
<li> </li>
<li><Link to="/auth">認証</Link></li>
</ul>
{/* ここから下が実際のコンテンツに置き換わる */}
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/index.html" component={Home} />
<Route exact path="/auth" component={Auth} />
<PrivateRoute path="/private" component={PrivatePage} auth="/auth" />
<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>
);
}
/**
* 認証状態を保持する変数
*/
var UserStatus = {
auth: false //true:ログイン, false:未ログイン
};
/**
* 簡易的な認証ページ
*/
class Auth extends Component{
constructor(props){
super(props);
this.state = {
auth: UserStatus.auth
}
this.onLogin = this.onLogin.bind(this);
this.onLogout = this.onLogout.bind(this);
}
onLogin(e){
e.preventDefault();
this.setState({auth:true});
UserStatus.auth = true;
}
onLogout(e){
e.preventDefault();
this.setState({auth:false});
UserStatus.auth = false;
}
render(){
let desc = UserStatus.auth? "現在ログイン中です":"ログインしていません";
let button = UserStatus.auth? <button onClick={this.onLogout}>ログアウト</button>:<button onClick={this.onLogin}>ログイン</button>;
return (
<div className={"item"}>
<h2>認証ページ</h2>
<p>{desc}</p>
<form>
{button}
</form>
</div>
);
}
}
/**
* ログインチェック付きRouter
*/
class PrivateRoute extends Component{
constructor(props){
super(props);
}
render(){
if( UserStatus.auth ){
return( <Route path={this.props.path} component={this.props.component} /> );
}
else{
return( <Redirect to={this.props.auth} /> );
}
}
}
/**
* 秘密のページ
*/
function PrivatePage(){
return(
<div className={"item"}>
<h2>南極</h2>
<img src="/image/nankyoku.png" />
<ul>
<li>ぺんぎん</li>
<li>アザラシ</li>
<li>オーロラ</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;
}
解説
認証チェックは独自実装が必要
ReactRouterには認証状態をチェックしてルーティングする機能が存在しないため、独自に実装する必要があるようです。
今回は<PrivateRoute>
Componentを新規に作成しました。
<Switch>
<PrivateRoute path="/private" component={PrivatePage} auth="/auth" />
</Switch>
このComponentが行っていることは非常にシンプルです。
認証状態を保持しているグローバル変数がtrue
になっていれば<Route>
を、false
なら<Redirect>
を返しているだけです。
class PrivateRoute extends Component{
constructor(props){
super(props);
}
render(){
if( UserStatus.auth ){
return( <Route path={this.props.path} component={this.props.component} /> );
}
else{
return( <Redirect to={this.props.auth} /> );
}
}
}
ログイン状態の切り替えは、こちらも簡易的に作成した<Auth>
Componentで行っています。ボタンを押したら認証状態を保持しているグローバル変数のtrue
とfalse
が入れ替わるだけのシンプルな物です。実際のアプリではここでサーバと通信して認証結果を取ってくることになります。
クラスでComponentを作成している関係で若干コードが長くなっていますが、原理としては非常に簡単ですね。
続き
参考ページ
- https://reacttraining.com/react-router/
- https://reacttraining.com/react-router/web/example/auth-workflow
このブログを応援する
お寄せいただいたお気持ちは全額サーバ代や次の記事を執筆するための原資として活用させていただいております。この記事が参考になった場合などぜひご検討ください。
同じカテゴリの記事
- はじめての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 #24 「ルーティングに対応する」URLパラメーター編 react-router@v5
- はじめてのReact #23 「ルーティングに対応する」基本編 react-router@v5
- はじめてのReact #22「ToDoアプリを作る」 後編