15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HALAdvent Calendar 2016

Day 16

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

Last updated at Posted at 2016-12-15

自己紹介

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

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

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

開発環境

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

使うのはcreate-react-appです。
これ自体の詳細は
Facebook公式のcreate-react-appコマンドを使ってReact.jsアプリを爆速で作成する
を参考にしていただけたらなと思います。

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

$ 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のtodoを簡略化したものになります。

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

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

まずTodoApp.jsxを書きます。

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

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

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

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

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

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

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

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

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

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

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

TodoConstants.js
import keyMirror from "keymirror"

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

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

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

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

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

この2行で終わりです!

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

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を書いていきましょう。

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の実装

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のオートバインドがなくなる問題。

これに関してはいくつか解決策があるのでこちらを参照ください。

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

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

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

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

ループのやり方はこちらに詳しく書いています。

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

最終系はこんな感じ

スクリーンショット 2016-11-11 4.38.40(2).png

あとがき

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

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

konojunya/flux_todo_sample

twitter -> @konojunya

15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?