React+Fluxxor+ajaxでfluxなTODOアプリ


Web+DB Pressのvol86と87で伊藤直也さんのReact.js+Fluxの記事があったので勉強してみました。

![](http://i.gyazo.com/fd734d641586edd23088fe61e224c87e.png)

vol86のReactだけだと外部のAPIとかとの連携のイメージがつきにくかったんですけど、vol87の記事のサンプルを動かしてみてやっと
とはいえまだまだですが汗

## やったこと
Reactに慣れてからfluxへという流れです。

- [ボタンを押すとカウンタの数字を変えるカウンタアプリをReactだけで](https://github.com/n0bisuke/react-study/tree/counter) 
- [カウンタアプリをfluxで](https://github.com/n0bisuke/react-study/tree/counter-flux)
- [todoアプリをfluxで](https://github.com/n0bisuke/react-study/tree/todo-flux)
- [todoアプリにajax通信を追加](https://github.com/n0bisuke/react-study/tree/todo-flux-ajax)

## まずはTODOアプリを作る

サンプルはこちらに置いておきます。 https://github.com/n0bisuke/react-study/tree/todo-flux

Flux構成のフレームワークであるFluxxorを使って、[vol87の記事](http://gihyo.jp/magazine/wdpress/archive/2015/vol87)では紹介してくれています。

早速ですが、実行するとこんな感じです。

![](http://i.gyazo.com/647651c91d4c36b242204cf4c18ebc72.gif)

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側に書きました。

```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>
```

データはこんな感じです。

```todos.json
[{
  "text": "ほげ"
 },
 {
  "text": "ふが"
 }
]
```

[ここ](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx)にapp.jsxの完成系があるのですが、以下で個別に説明してみます。

### 1. Action(Action Creator)にlaadTodosメソッドを追加

まず、 **Actionは`定数で定義された、アクションの識別子`と`{value:1}などの入力値に相当するオブジェクト`のペアを指す**とのことです。ということで`LOAD_TODOS_SUCCESS`という識別子を定義しておきます。

> [7行目](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L7)

```app.jsx
/*省略*/

var constants = {
  ADD_TODO:    "ADD_TODO",
  TOGGLE_TODO: "TOGGLE_TODO",
  LOAD_TODOS_SUCCESS: "LOAD_TODOS_SUCCESS" //追記
};

/*省略*/
```

>[57行目付近](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L57-L63)

メソッド内に`$.ajax()`での処理を記述してきます。
ajax処理の完了時`.done()`の処理で`this.dispatch()`でdataをDispacher経由でStoreに送ります。

```app.jsx
/*省略*/

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に送られた際に実行する処理とその紐付けです。

>[17行目](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L17)

```app.jsx
/*省略*/
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メソッド`に紐付けています。

> [36行目付近](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L36-L48)

```app.jsx
  /*省略*/
  
  //追加
  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行目)](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L61)の`{data:data}`の部分が送られてきます。

つまり、http通信でGETした内容(todos.jsonの内容そのまま)です。

Action側で非同期処理を書き、処理完了時点のデータをStoreに送り、Storeの中では非同期処理は行わないようにするとデータフローが明確になって良いとのことです。

[47行目](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L47)で`this.emit('change');`と呼んでいます。Storeが管理するデータに変更があったことをViewに伝えてあげます。
これでViewまで伝えてあげたらあとは通常のTODOアプリと同じです。

### 3. View側でActionCreatorを発火してあげる

1と2で作った処理のトリガーはView側になります。
今回はViewのロード時にこのアクションを実行します。

>[80行目](https://github.com/n0bisuke/react-study/blob/todo-flux-ajax/src/app.jsx#L80)

```app.jsx
  /*省略*/
  
getInitialState: function() {
    this.getFlux().actions.loadTodos(); //追加: viewの呼び出し時にロード
    return { newTodoText: "" };
  },
  
    /*省略*/
```

view側の`getInitialStateメソッド`内で`loadTodos()`を呼び出してあげて、読み込み時にAjaxでデータを取得する処理の完成です。

## まとめ

サーバー側の処理を書くのがダルかったのでPOSTでデータ追加とかはやらなかったけど、同じような雰囲気で書けると思います。

Fluxの流れを理解できた気がする...!

次はMilkcocoaと連携してみたいと思います!
→ http://qiita.com/n0bisuke/items/f28016de82136a2a4d26