Web+DB Pressのvol86と87で伊藤直也さんのReact.js+Fluxの記事があったので勉強してみました。
vol86のReactだけだと外部のAPIとかとの連携のイメージがつきにくかったんですけど、vol87の記事のサンプルを動かしてみてやっと
とはいえまだまだですが汗
やったこと
Reactに慣れてからfluxへという流れです。
まずはTODOアプリを作る
サンプルはこちらに置いておきます。 https://github.com/n0bisuke/react-study/tree/todo-flux
Flux構成のフレームワークであるFluxxorを使って、vol87の記事では紹介してくれています。
早速ですが、実行するとこんな感じです。
Fluxの解説などはWeb+DB Pressを読みましょうw
Fluxxorにajax的な処理を追加してみる
Web+DB Pressの記事では説明が少し割愛されていた部分です
サーバー上にあるjsonデータをHTTPリクエストで取得してTODOリストとして表示させる作りに変えてみます。ちなみに、サンプルはこちらに置いてきます。 https://github.com/n0bisuke/react-study/tree/todo-flux-ajax
非同期通信系の処理はActionを起点にしましょうとのことでActionから処理を追って説明をしてみます。 (ツッコミ歓迎!!)
0. jQuery読み込みとJSONデータ用意
jQueryの$.ajax()
を使ってみます。jQueryのロードはindex.html側に書きました。
<html>
<head>
<title>TODOリスト</title>
</head>
<body>
<div id="app-container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script charset="utf-8" src="dest/app.js"></script>
</body>
</html>
データはこんな感じです。
[{
"text": "ほげ"
},
{
"text": "ふが"
}
]
ここにapp.jsxの完成系があるのですが、以下で個別に説明してみます。
1. Action(Action Creator)にlaadTodosメソッドを追加
まず、 Actionは定数で定義された、アクションの識別子
と{value:1}などの入力値に相当するオブジェクト
のペアを指すとのことです。ということでLOAD_TODOS_SUCCESS
という識別子を定義しておきます。
/*省略*/
var constants = {
ADD_TODO: "ADD_TODO",
TOGGLE_TODO: "TOGGLE_TODO",
LOAD_TODOS_SUCCESS: "LOAD_TODOS_SUCCESS" //追記
};
/*省略*/
メソッド内に$.ajax()
での処理を記述してきます。
ajax処理の完了時.done()
の処理でthis.dispatch()
でdataをDispacher経由でStoreに送ります。
/*省略*/
var actions = {
//追加
loadTodos: function(){
$.ajax({
url: "./todos.json"
}).done(function(data){
this.dispatch(constants.LOAD_TODOS_SUCCESS, {data: data});
}.bind(this));
},
/*省略*/
this.dispatch()
内の(constants.LOAD_TODOS_SUCCESS, {data: data}
の部分がStoreに対して操作を要求するメッセージ(=アクション)となるみたいです。
**.bind(this)
を書いておかないと動かないので注意!**これWeb+DB Press側のコードミスかも。JSのthisの罠。
2. Storeでアクションとメソッドの紐付け(bind)
先ほどのアクションがStoreに送られた際に実行する処理とその紐付けです。
/*省略*/
var TodoStore = Fluxxor.createStore({
initialize: function() {
this.todoId = 0;
this.todos = {};
this.bindActions(
constants.ADD_TODO, this.onAddTodo,
constants.TOGGLE_TODO, this.onToggleTodo,
constants.LOAD_TODOS_SUCCESS, this.onLoadTodosSuccess //追記
);
},
/*省略*/
this.bindActions()
で先ほど定義したLOAD_TODOS_SUCCESS
のアクションがStoreにメッセージとして送られて来た際のメソッドを紐付けます。ここではonLoadTodosSuccessメソッド
に紐付けています。
/*省略*/
//追加
onLoadTodosSuccess: function(payload){
payload.data.forEach(function(item){
var id = ++this.todoId;
var todo = {
id: id,
text: item.text,
complete: false
};
this.todos[id] = todo;
}.bind(this));
this.emit('change');
},
/*省略*/
onLoadTodosSuccessメソッド
の中身です。 idをインクリメントしながらデータを追加していく処理になってます。
payload
にさっき(61行目)の{data:data}
の部分が送られてきます。
つまり、http通信でGETした内容(todos.jsonの内容そのまま)です。
Action側で非同期処理を書き、処理完了時点のデータをStoreに送り、Storeの中では非同期処理は行わないようにするとデータフローが明確になって良いとのことです。
47行目でthis.emit('change');
と呼んでいます。Storeが管理するデータに変更があったことをViewに伝えてあげます。
これでViewまで伝えてあげたらあとは通常のTODOアプリと同じです。
3. View側でActionCreatorを発火してあげる
1と2で作った処理のトリガーはView側になります。
今回はViewのロード時にこのアクションを実行します。
/*省略*/
getInitialState: function() {
this.getFlux().actions.loadTodos(); //追加: viewの呼び出し時にロード
return { newTodoText: "" };
},
/*省略*/
view側のgetInitialStateメソッド
内でloadTodos()
を呼び出してあげて、読み込み時にAjaxでデータを取得する処理の完成です。
まとめ
サーバー側の処理を書くのがダルかったのでPOSTでデータ追加とかはやらなかったけど、同じような雰囲気で書けると思います。
Fluxの流れを理解できた気がする...!
次はMilkcocoaと連携してみたいと思います!
→ http://qiita.com/n0bisuke/items/f28016de82136a2a4d26