今話題のFlux + Reactを最速で体感しよう！

# 自己紹介

じゅんじゅんというニックネームで、関西を拠点に活動しているフロントエンドエンジニアです。

HAL大阪の2回生です👍 (2016.11.10現在)

よくstart up系イベントに行くので、大阪らへんの方は会いましょう！

# 開発環境

今回は、ReactがメインではなくFluxを導入したいけどどんなもんなのか頭で理解でききらん！や、チョットナニイッテルカワカラナイデスっていう方向けの記事です。
なので、開発のbabelがどうのとかwebpackがどうのとかはしんどいので、コマンド1つでReactのアプリケーションの雛形を作ってくれるFacebook公式のものを使っていきたいと思います。

使うのは[create-react-app](https://github.com/facebookincubator/create-react-app)です。
これ自体の詳細は
[Facebook公式のcreate-react-appコマンドを使ってReact.jsアプリを爆速で作成する](http://qiita.com/chibicode/items/8533dd72f1ebaeb4b614)
を参考にしていただけたらなと思います。

まずインストールから初めて行きます。

```
$ npm install -g create-react-app
```

インストールできたらコマンドでプロジェクトを作っていきます。

```
$ create-react-app <project名>
```

ここまででReactを書き始める準備はもうバッチリになっています。

ひとまず今回はCSSとかは記事の内容と関係ないのでcssファイルとlogoなどの無駄なファイルを消していきます。

最終的に

```
project_name/
- node_modues/
- public/
    - favicon.ico
    - index.html
- src/
    - index.js
- .gitignore
- package.json
- README.md
```

と言う構成にしてください。

# Flux

Fluxの説明などはいくらでもQiitaやhatenablogなどに乗ってるので今回は省きます。

今回作るTodoは[facebook/flux](https://github.com/facebook/flux)のtodoを簡略化したものになります。

では、Fluxを導入するために`src/`を以下のように変更してください。

```
src/
- actions/
    - TodoActions.js
- constants/
    - TodoConstants.js
- components/
    - TodoApp.jsx
- stores/
    - TodoStore.js
- dispatcher/
    - AppDispatcher.js
```

まず`TodoApp.jsx`を書きます。

```js:TodoApp.jsx
import React from "react"

export default class TodoApp extends React.Component {

  render(){
    return(
      <h1>Hello</h1>
    )
  }

}
```

![スクリーンショット 2016-11-11 2.55.11（2）.png](https://qiita-image-store.s3.amazonaws.com/0/90347/8ef38c62-d72d-c0d4-1792-fbb9e9e1c44a.png)

このように表示されたでしょうか。

今回はfacebookのfluxリポジトリに合わせるためにフォルダ構成を`actions`,`constants`,`stores`,`dispatcher`に分けていきたいと思います。

それぞれを簡単に説明すると

- actions
    - dispatcherへ誰に送るべきかを添えて送る。
- constants
    - 決め事。
- stores
    - データをためておく場所、処理自体を行う。
- dispatcher
    - storeへ何をどう変更するのはを伝える。

といった感じでしょうか。

ではまず、約束から決めていきましょう。

この**constants**は、それぞれ動作を表します。

今回は単純さを一番にしているので、作成と削除だけにしたいと思います。

その場合、動作としては`create`と`destory`になると思います。（removeやdeleteでも構わないと思いますが予約語などに気をつけてください。今回はfacebookに従います。）

この2つの動作を`constants`へ書いていきたいと思います。

```js:TodoConstants.js
import keyMirror from "keymirror"

export default keyMirror({
  TODO_CREATE: null,
  TODO_DESTROY: null
})
```

今回使っている`keyMirror`ですが、多分nullの方へkeyを転写してるだけなので自分で書いても問題ありません！

続いて`dispatcher`を書いていきます。

といっても、`dispatcher`自体はfluxのモジュールの中にあるのでそれを使っていきたいと思います。

```js:AppDispatcher.js
import { Dispatcher } from "flux"
export default new Dispatcher()
```

この２行で終わりです！

続いて`action`を書いていきたいと思います。

```js:TodoActions.js
import AppDispatcher from "../dispatcher/AppDispatcher"
import TodoConstants from "../constants/TodoConstants"

var TodoActions = {

  create(text){
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_CREATE, // 誰に
      text: text // 何を渡すのか
    })
  }

  destory(id){
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_DESTROY,
      id: id
    })
  }

}

export default TodoActions
```

これで`Action`はdispatcherに向けてだけ投げてればいいので他のことを意識する必要がありません。

何を誰に渡すのかだけを見てdispatcherさんに渡します。

これもfluxのいいところですね。

では、`stores`を書いていきましょう。

```js:TodoStore.js
import AppDispatcher from "../dispatcherAppDispatcher"
import { EventEmitter } from "events"
import TodoConstants from "../constants/TodoConstants"
import assign from "object-assign"

var CHANGE_EVENT = "change" // chenge evnetを定数にする

var _todos = {} // 初期化

/*
*  ここから処理本体を書き始める
*/
var create = (text) => {
  var id = (+new Date() + Math.floor(Math.random() * 999999)).toString(36);
  _todos[id] = {
    id: id,
    text: text
  }
}

var destory = (id) => {
  delete _todos[id]
}

var TodoStore = assign({},EventEmitter.prototype,{

  getAll(){ // 今のtodo全てを返す
    return _todos
  }

  emitChange(){ // 何かアクションがあったことを知らせる
    this.emit(CHANGE_EVENT)
  }

  addChangeListener(callback){ // リスナーに追加
    this.on(CHANGE_EVENT, callback)
  }

  removeChangeListener(callback){ // リスナーから削除
    this.removeListener(CHANGE_EVENT, callback)
  }

})

AppDispatcher.register((action)=>{
  var text;

  switch(action.actionType){ // actionTypeでswitchする
    case TodoConstants.TODO_CREATE: // createなら
      text = action.text.trim()
      if(text !== ''){
        create(text)
        TodoStore.emitChange()
      }
      break;

    case TodoConstants.TODO_DESTROY:　// destroyなら
      destroy(action.id)
      TodoStore.emitChange()
      break;

    default:
      // no
  }
})
export default TodoStore
```

これで処理周りは全てできたので、viewを作っていきましょう。

`TodoApp.jsx`の実装

```js:TodoApp.jsx
import React from "react"
import TodoStore from "../stores/TodoStore"
import TodoActions from '../actions/TodoActions';

var getTodoState = () => {
  return TodoStore.getAll()
}

export default class TodoApp extends React.Component {

  constructor(){
    super()
    this.state = {
      value: "",
      todos: getTodoState()
    }
  }

  componentDidMount(){
    TodoStore.addChangeListener(this._onChange.bind(this))
  }

  componentWillUnmount(){
    TodoStore.removeChangeListener(this._onChange.bind(this));
  }

  render(){
    var todoElements = [];
    var todos = this.state.todos;
    for(var key in todos){
      todoElements.push( // todoの分だけ配列に追加する
        <li key={key} id={todos[key].id}>
          <span style={{marginRight: "30px"}}>{todos[key].text}</span>
          <button onClick={this._destroy.bind(this)}>&times;</button>
        </li>
      )
    }
		
    return(
      <div>
        <input type="text" value={this.state.value} onChange={this._Input.bind(this)}/>
        <button onClick={this._submit.bind(this)}>Add.</button>
        <ul>
          {todoElements} {/*配列を展開する*/}
        </ul>
      </div>
    )
  }

  _destroy(e){
    var id = e.target.parentNode.id
    TodoActions.destroy(id) // 消したい投稿のidを渡すだけ！
  }

  _submit(){
    TodoActions.create(this.state.value) // テキストを渡すだけ！
    this.setState({ // 追加したら入力欄は空にする
      value: ""
    })
  }

  _Input(e){ // 入力中(onChange)でstateを書き換える	
    this.setState({
      value: e.target.value
    })
  }

  _onChange(){
    this.setState(getTodoState())
  }

}
```

複数Reactならではのハマるポイントがあるので説明を付け加えます。

まず、ES2015でReactを書くとthisのオートバインドがなくなる問題。

これに関してはいくつか解決策があるので[こちら](http://qiita.com/konojunya/items/fc0cfa6a56821e709065)を参照ください。

次に、入力された文字が入る`this.state.value`なんですが、inputのvalueとしても使いたいです。

なので、`onChange`などで`state`を書き換えまくってinputのvalueにも展開していく感じにします。

最後に、Reactには配列をループしてくれるものがありません。

なので自分でループを作り、それを展開しないといけません。

ループのやり方は[こちら](http://qiita.com/konojunya/items/cb026a2aa3df1837d587)に詳しく書いています。

これでもうTodoができていると思います！

最終系はこんな感じ

![スクリーンショット 2016-11-11 4.38.40（2）.png](https://qiita-image-store.s3.amazonaws.com/0/90347/3072dc48-a8c5-9744-e3aa-bc868a61502f.png)


# あとがき

かなり機能を絞って作ったのでそんなに難しくはないと思うし、fluxってこんなもんか〜程度に受け取ってもらえると有り難いです！

コードはgithubに置いているのでcloneしたらすぐ動かすことができると思います！

[konojunya/flux_todo_sample](https://github.com/konojunya/flux_todo_sample)

twitter -> [@konojunya](https://twitter.com/konojunya/)