React使ってSPAを作るよ(17)の続きです。
なんとなくコンテンツはできてきたので、そろそろユーザー認証のあたりを考えていきたいです。
あとで変えるかもしれませんが、今のところ仕様は下記のような感じを想定しています。
ゲストユーザーの場合
- 記事一覧は見ることができる
- タグ絞り込み機能も使える
- 読んだ人リスト、コメント、コメント入力フォームは表示されない
- 記事を追加することはできない
- navの記事追加ボタンを押したらログインフォームが表示される
- navのアカウントボタンを押したらログインフォームが表示される
- アカウントアイコンはデフォルトの画像が表示される

モックを用意するのが面倒なので実装済みの動作をGIFにしました!
ログインユーザーの場合
- 記事一覧を見ることができる
- タグ絞り込み機能も使える
- 読んだ人リスト、コメント、コメント入力フォームも表示される
- 記事にコメントを投稿できる
- 自分のコメントは削除ボタンが表示され、削除できる
- (コメントの編集は検討する)
- 自分の追加した記事は削除ボタンが表示され、削除できる
- 記事を追加できる
- navの記事追加ボタンを押したら記事追加フォームが表示される
- navのアカウントボタンを押したらアカウント情報設定フォームが表示される
- アカウントアイコンの画像を登録できる
というふうに分けたいと思います。
あ、minamiという架空のサービス名は、以前このページのイメージカラーをピンクにしたのと同じく、AKBファンの同僚がたかみな神推しだからです。
Reactコンポーネントのrender内でif文を使う
まだ認証部分の実装はしていませんが、ひとまずログインフォームのパーツを作っていきます。
ログインユーザーの記事追加フォームはこれまでと同じですね。
URLFormコンポーネントが入っています。
ログインしていないユーザーのときはここにURLFormのかわりにログインフォームのコンポーネントを入れます。
React使ってSPAを作るよ(15)で作ったナビゲーションコンポーネントに、minamiロゴやアカウントボタンを追加しました。
//ナビゲーションコンポーネント
var Navigation = React.createClass({
propTypes:{
text: React.PropTypes.string
},
render: function() {
var test = true;
var accountImage = {
backgroundImage : "url(" + this.props.accountImage + ")"
};
return (
<nav id="menu">
<input type="radio" name="menu" id="menu00" defaultChecked="checked" /><label htmlFor="menu00" className="overlay-close">×</label>
<input type="radio" name="menu" id="menu01"/><label htmlFor="menu01">
<svg viewBox="0 0 31 37">
<path d="M26.5,36.5h-22c-2.2,0-4-1.8-4-4v-28c0-2.2,1.8-4,4-4h22
c2.2,0,4,1.8,4,4v28C30.5,34.7,28.7,36.5,26.5,36.5z M27.5,18.5v-12c0-1.1-0.9-2-2-2h-20c-1.1,0-2,0.9-2,2v12c0,1.1,0.9,2,2,2h20
C26.6,20.5,27.5,19.6,27.5,18.5z M4.475,26.291h22 M4.475,31.291h22"/>
</svg>
</label>
{(() => {
if (test === true) {
return <URLForm />;
}
else {
return <LoginBox text={'記事を追加するにはログインしてください。'} />;
}
})()}
<input type="radio" name="menu" id="menu02" /><label htmlFor="menu02">
<svg viewBox="0 0 42.387 43.79">
<path d="M30.5,15.5c0,8.284-6.716,15-15,15s-15-6.716-15-15s6.716-15,15-15
S30.5,7.216,30.5,15.5z M15.5,5.5c-5.523,0-10,4.477-10,10s4.477,10,10,10s10-4.477,10-10S21.023,5.5,15.5,5.5z M37.966,39.972
l-7.221-9.585c-0.993-1.318-2.883-1.584-4.201-0.591l0,0c-1.318,0.993-1.584,2.883-0.591,4.201l7.221,9.585
c0.993,1.318,2.883,1.584,4.201,0.591l0,0C38.693,43.18,38.959,41.29,37.966,39.972z"/>
</svg>
</label>
<TagList data={this.props.data} />
<input type="radio" name="menu" id="menu03" /><label htmlFor="menu03" style={accountImage}>
<svg version="1.1" x="0px" y="0px" viewBox="0 0 27 32.5">
<path d="M13.5,0.5c-4.971,0-9,4.029-9,9s4.029,9,9,9s9-4.029,9-9
S18.471,0.5,13.5,0.5z M26.5,32c0-6-7.477-10-13-10s-13,4-13,10H26.5z"/>
</svg>
</label>
{(() => {
if (test === true) {
return <Account />;
}
else {
return <LoginBox text={'ログイン'} />;
}
})()}
</nav>
);
}
});
分岐用の記述が増えていますので、ひとつずつ説明していきますね。
var test = true;
if (test === true) {
このtestというのは、ログイン状態かどうかということの判定のかわりに使っています。
本来だったらここは「誰がログインしているか」っていうデータまで渡さないといけないところなのですが、今は認証機能が実装されていないので、このtrue/falseを切り替えて画面の確認をしています。
で、ご覧のとおり
{(() => {
if (test === true) {
return <URLForm />;
}
else {
return <LoginBox text={'記事を追加するにはログインしてください。'} />;
}
})()}
{(() => {
if (test === true) {
return <Account />;
}
else {
return <LoginBox text={'ログイン'} />;
}
})()}
この2箇所で、ログイン中ならURLFormコンポーネント/Accountコンポーネントを表示、ログインしていなければLoginBoxコンポーネントを表示しています。
さて、今回新たにLogin.jsxというファイルを用意しました。
var React = require('react');
//ログイン
var LoginBox = React.createClass({
render: function() {
return (
<form id="login-box">
<p>{this.props.text}</p>
<input type="mail" placeholder="example@example.com" />
<input type="password" placeholder="password" />
<input type="submit" className="button01" value="ログイン" />
<div className="checkbox-list"><input type="checkbox" id="login-save" /><label htmlFor="login-save">ログイン情報を保存</label></div>
<button className="button02">新規アカウント登録</button>
</form>
);
}
});
module.exports = LoginBox;
ログインしていないときに表示されるログインフォームです。
先ほどナビゲーションコンポーネントから渡されたtextがp要素の中に入るわけですね。
同じパーツでも、呼び出す場所によって「ここだけテキストを変えたい」っていうことが可能です。
Account.jsxも新しく作りました。
var React = require('react');
//アカウント
var Account = React.createClass({
render: function() {
return (
<form id="account-config">
<h2>アカウント情報</h2>
<input type="text" id="account-name" placeholder="ユーザー名" defaultValue="やまだたろー"/>
<input type="mail" placeholder="example@example.com" defaultValue="example@example.com" />
<input type="password" placeholder="password" defaultValue="password" />
<input type="submit" className="button01" defaultValue="アカウント情報を変更" />
<button className="button02">アカウントを削除</button>
</form>
);
}
});
module.exports = Account;
さすがにこのくらいのコンポーネントなら簡単に作れるようになってきましたね。
将来的にはここにアイコン画像を登録するためのパーツを入れていくことになります。
とりあえず今回はここまで!
