React を導入した
フロントエンド開発
~フレームワークを利用した
シングルページアプリケーションの制御~
2015.12
GMOインターネット
次世代システム研究室
松井 大介
管理画面のフロントエンドに
Reactを導入したっていう話です。
アジェンダ
• 絶対王者 Angular vs 挑戦者 React
• React での SPA 設計
1.コンポーネントを分ける
2.ReactRouter
3.jQuery との共存
アジェンダ
• 絶対王者 Angular vs 挑戦者 React
• React での SPA 設計
1.コンポーネントを分ける
2.ReactRouter
3.jQuery との共存
GMOスマートリザーブの
ご紹介
飲食店向け予約一元管理
2015年4月-8月
次世代システムが
サービス立ち上げを
支援しました
【日本】
マネージャー 1名
ベトナムブリッジ 1名
【ベトナム】
ベトナム 3名
デモ
フロントエンド
実装期間1ヶ月弱
システムの特徴
• バックエンド
データ操作用 API サーバを用意。
(外部連携を意図)
• 管理画面= フロントエンドだけ
1. JS による SPA から API を叩く。
2. 管理画面なので
そこまで厳しいパフォーマンス要件はない
SPA
シングルページアプリケーション
1.HTML のレンダリングを
全てクライアントサイドでやる!
2.サーバにアクセスするのはAPIで
データ取得・保存するときだけ!
SPA
シングルページアプリケーション
1.HTML のレンダリングを
全てクライアントサイドでやる!
2.サーバにアクセスするのはAPIで
データ取得・保存するときだけ!
ここぞとばかりに
新しい
JSフレームワーク
使いたい!!!
JS フレームワーク戦国時代
Googleトレンド
https://www.google.co.jp/trends/explore#q=angular%20js%2C%20backbone%20js%2
C%20react%20js&cmpt=q&tz=Etc%2FGMT-9
絶対王者 Angular
• Google が開発
• 高機能
フロントエンドMVC全部盛り
双方向データバインディング
ヴァリデーションとか全自動機能多い
• HTML拡張
デザイナーでも見やすい
React が注目された理由
• Facebook / Instagram で開発+利用
• 双方向データバインディングに対する懐疑
(高機能すぎて複雑、処理が重い)
React の斬新なコンセプト
• VirtualDOM
1.実装者は仮想のDOMを記述
2.React は変更発生した場合仮想DOMの
差分を確認し、リアルDOMを更新
⇒ 軽量な描画コスト
• 一方向なデータフロー
かならず同じ順序で処理される。
状態が変わるたびに再描画される。
⇒ 保守しやすい
React でできること
• 画面描画処理の統一化
React のライフサイクルに合わせて描画
• 画面パーツのコンポーネント化
共通のパーツ整理
描画パフォーマンス
https://www.codementor.io/reactjs/tutorial/reactjs-vs-angular-js-performance-
comparison-knockout
比較項目 Angular React
機能 高機能
管理画面構築は
非常に楽。
実装が必要
デザイナー親和性 高
基本HTML
低
JSX+カスタムタグは
読みづらい
パフォーマンス 低 高
将来性 1系×(打ち切り)
2系??
枯れてない。
どんどん変わる。
好み もりもりすぎなん
じゃないの?
一方向なデータフロー
が読みやすい!
学習の平易さを優先し
React 採用しました★
React での SPA 設計
アジェンダ
• 絶対王者 Angular vs 挑戦者 React
• React での SPA 設計
1.コンポーネントを分ける
2.ReactRouter
3.jQuery との共存
画面パーツを
React コンポーネント化
React での設計ポイント
• 画面パーツをコンポーネントにする。
• 親コンポーネント子コンポーネントで
値の受け渡し+イベントを整理する。
DaySelect
コンポーネント
TableSchedule
コンポーネント
ReservationFooterコンポーネント
Modal
コンポーネント
ReserveForm
コンポーネント
var HomeScreen = React.createClass(){
render : function() {return
<div>
<DaySelect/>
<TableSchedule/>
<ReservationFooter/>
<Modal>
<ReserveForm/>
</Modal>
</div>})..};
JSX+コンポーネントタグ
=JS内のrender()中に
HTMLと独自タグを記述
var DaySelect = React.createClass(){
//初期化
getInitialState(){...},
//描画前
componentWillMount() {...},
//描画
render() {...},
//描画後
componentDidMount() {...},
//クリックイベント
onClickBotton() {...}
}
http://qiita.com/kawachi/items/092bfc281f88e3a6e456
http://qiita.com/kawachi/items/092bfc281f88e3a6e456
ライフサイクルさえ
把握すればReact
を制したも同然
TableSchedule
コンポーネント
予約時間を
クリック
var HomeScreen = React.createClass(){
render : function() {return
<div>
<DaySelect/>
<TableSchedule
onClickReservation={this.onClickReservation}/>
<ReservationFooter/>
<Modal>
<ReserveForm/>
</Modal>
var HomeScreen = React.createClass({
onClickReservation: function(reservation)
{
this.setState({
inputReservation: reservation,
isModalOpen: true,
doneButtonName:‘予約修正’,
cancelButtonName:'予約取消'
}); },
setState()
⇒再描画
ReserveForm
コンポーネント
修正ボタン
クリック
var HomeScreen = React.createClass(){
render : function() {return
<div>
<DaySelect/>
<TableSchedule onClickReservation={this.onClickReservation}/>
<ReservationFooter/>
<Modal>
<ReserveForm onDone={this.updateReservation}/>
</Modal>
</div>})..};
updateReservation: function(reservation) {
request.post(apiHost
+ ‘/shops/’
+ this.props.shopId
+ ‘/reservations’)
.query({token:accessToken})
.send(query)
.end(function (err, res) {
//保存完了したら戻る処理
};
};
※request オブジェクトは superagent.js をラップ
React コンポーネント理解のポイント
• ライフサイクルメソッドで生成される!
• setState() で再描画される!
React Router
React Router
• ルーティングライブラリ
• URL と Reactコンポーネントの対応定義
• ヘッダー、サイドバー、フッターの共通化
SPA=1画面制御
ログイン画面 ホーム画面
週間スケジュール
画面
すべて app.js からRouting される
ログイン画面
login_screen
予約ページフッター
reservation_footer
週間スケジュール
week_schedule
ホーム画面
home_screen
メニューヘッダー
menu_header
メニューヘッダー
menu_header
予約ページフッター
reservation_footer
すべて app.js からRouting される
<Route name="app" path="/" handler={App}>
<Route
name="home"
path="/shops/:shopId“
handler={HomeScreen}/>
<Route
name="weekSchedule“
path="/shops/:shopId/week_schedule“
handler={WeekScheduleScreen}/>
<Route
name="login"
path="/"
handler={LoginScreen}/>
<DefaultRoute handler={LoginScreen}/>
</Route>
一元管理
jQuery との共存
jQuery UI Datepicker
jQuery UI Datepicker
普通に使うと
動かない!
jQuery 初期化は画面描画時
<script>
//画面描画後に呼ばれる jQuery の処理
$(document).ready(function(){
// datepckr に機能をバインドする
$("#datepckr").datepicker();
});
</script>
<input type="text" id="datepckr" />
React は setState で何度も再描画
getInitialState : 初期化時に1回だけ
componentWillMount : render 前処理
render : 描画処理
componentDidMount : render 後処理
componentWillUpdate : State 変更後 render の前
componentDidUpdate : State 変更後
componentWillUnmount :コンポーネント削除前
=クリックイベント処理のバインドが外れてしまう
http://qiita.com/kawachi/items/092bfc281f88e3a6e456
render 直後であれば DOM 操作可能
getInitialState : 初期化時に1回だけ
componentWillMount : render 前処理
render : 描画処理
componentDidMount : render 後処理
componentWillUpdate : State 変更後 render の前
componentDidUpdate : State 変更後
componentWillUnmount :コンポーネント削除前
componentDidMount: function () {
self = this;
$('.input-date').datepicker(
{
//Datepicker 初期化のための値
dateFormat: 'yy-mm-dd',
//選択時のイベント処理
onSelect: function(dateVal) {
//親コンポーネントに変数渡すなどの処理
}
}
);
}
jQuery が data-reactid を
いじってしまうと
破壊されるので注意
<section data-reactid=".0.1.0.1">
<div data-reactid=".0.1.0.1.0">
<dl data-reactid=".0.1.0.1.0.0">
<dt data-reactid=".0.1.0.1.0.0.0">
他にがんばったところ
Canvas in React
やらなかったこと
• サーバサイドレンダリング
主にSPAのSEO対策用処置。
管理画面なのでSEO関係なかった。
• Flux
開発期間の都合であきらめた。
今後改善できる部分。
まとめ
• Angular もいいけど React が平易そう
• React での SPA 設計
1.コンポーネント化が基本
2.ReactRouterで統一的に画面遷移制御
3.jQuery との共存の方法は
ライフサイクルを把握する
ご清聴ありがとうございました
アジェンダ
• 絶対王者 Angular vs 挑戦者 React
• React での SPA 設計
1.コンポーネントを分ける
2.ReactRouter
3.jQuery との共存
• もうちょっとがんばれば Flux
改善できそうなところ
改善できるところ
• もっと Flux をやるなら
良く見るFluxの図
公式にあるFluxの図
(実はシンプル)
• View
= React でつくった画面。
onClick などイベントがあればActionを呼ぶ。
• Action
onClickなどのイベント処理の集約クラス。
イベントが発生したら Dispatcher を呼ぶ。
渡すデータのことをペイロードと呼ぶ。
• Dispatcher
Actionからデータ(ペイロード)をもらって Store を操作
するクラス。
• Store
Ajax や Localstorage などデータ取得・保存系の処理を行
うクラス。
結局Fluxとは
一方向MVC
• Model ≒ Store
• View = View
• Controller ≒ Action + Dispatcher
※厳密には違うが、理解の取っ掛かりに
流れは一方向
Fluxに変更する上で必要なこと
たとえば HomeScreen コンポーネントなら
画面描画系 ⇒ React コンポーネント
(いままで通り)
イベント系
onClickReservation ⇒ Action クラスへ
保存イベント系
onSave ⇒ Action + Dispatcher クラスへ
保存処理
request.post (ajax) ⇒ Store クラスへ

React を導入した フロントエンド開発