React.js, Flux, CofeeScriptで試作したメモ

#React.js, Flux, CofeeScriptで試作したメモ

##環境

* reactjs
* Fluxxor
* CoffeeScript
* react-bootstrap

###JSXのCompile
最初[CoffeeScriptでReactJS環境を構築したメモ](http://qiita.com/yasei_no_otoko/items/490a5115a2f1d0ca3109)
に従って、**coffee-react**を使用して見たが、
素のJsxコンパイラではエラーにならない所がエラーになってしまったので、
JsxファイルでComponentの記述のみ行い、CoffeeScriptは別ファイルで
開発する事にした。
Flux,Action,Store,HandlerはCoffeeScriptファイルに記述する。
```
$w.flux = new Fluxxor.Flux()
$w.commonStore=new $c.CommonStore;
$w.flux.addStore("COMMON",$w.commonStore)
$w.flux.addActions($c.actions)
$w.FluxMixin = Fluxxor.FluxMixin(React)
$w.StoreWatchMixin = Fluxxor.StoreWatchMixin
$w.common=$w.flux.stores.COMMON
```

###StateとPropについて
Stateは最上位のComponentである Applicationにのみ定義、
下位のComponentにはPropで伝達する。なお $w.fluxは、
Applicationにflux propとして定義する。
```
React.render(<$w.Application flux={$w.flux}/>, document.getElementById('content'));
```

###Global変数の使用
今回は、参照しやすさを優先して下記のGlobal変数を使用した。

* $c - 共通Coffee Fileで使用するGlobal変数
* $w - 画面単位のCoffee Fileで使用するGlobal変数

以下に例を示す

* $c.constants - 共通で使うDispach 定数
* $c.actions - 共通で使うAction
* $c.CommonStore - 共通で使うStore
* $c.XXX - 共通で使う関数等
* $w.flux - Fluxxorのインスタンス
* $w.common - CommonStoreのインスタンス
* $w.app - 最上位Compnent Applicationのインスタンス

###onChange,onClick等のHandlerについて。
CoffeeScriptファイルに、Global定義

以下に例を示す

* $w.handleChange
* $w.handleClick

各Componentは、Name Propertyで例えば"search#loginId"と指定した物を
共通のHandlerで、この例であれば state.search.loginIdの値をonChange
eventにより、更新する。（setState functionで）

stateを階層構造にする事により、Form単位のデータの取得が一括で出来る。

onClickの場合は、Name Property判断して当該処理を行う。

尚一部　Componentで Name Propertyが無い場合はIDで行う。

###getStateFromFlux

onChange eventでStoreからstateにCopyするFunctionは以下の様に記述する。

Storeでは、this.data以下にstateにCopyされる変数を置く。

lodashのcloneDeepを使用する。
```
  getStateFromFlux: function() {
    return {
      common:_.cloneDeep($w.common.data)
      };
  },
```

###Storeの管理するstateとApplicationの管理するstateの分離
![status.jpg](https://qiita-image-store.s3.amazonaws.com/0/20387/f4a0efe9-f64a-9ca5-aaa8-f34c862f987f.jpeg)

上記の様に使い分けています。

Tableで Storeで　Ajaxで取り込んだものを Inlineで編集する場合は、
両方に該当してしまいますので、Storeで取り込んだものをchange以外のevent
を emitして、Store管理からApplication管理にCopyしています。
```
$w.rcdStore.on("rcdComplete_login", ->
  rcdLogin=_.cloneDeep($w.app.state.rcd.login)
  loginTemp={
    login:$w.app.state.login
  }
  loginTemp.login.rcds=rcdLogin.rcds
  loginTemp.form=rcdLogin.rcd
  loginTemp.login.selRow=rcdLogin.selRow
  $w.app.setState(loginTemp)
)
```

###react-bootstrapを使用していて、InputのDomNodeが取れなかった場合
refに値をsetして、this.refs["refの値"].getDOMNode() で取れると思ったのですが、
react-bootstrapのInput componentでは取れませんでした。
素の&lt;input&gt; componentを使用する必要がありました。

その後調べた所、getInputDOMNode()というHelper Methodを使用すれば良いそうです。

###動的に複数行のレンダリングを行う場合。
下記のSelect componentを参考にして下さい。
```
var b = ReactBootstrap;
$c.SelectOption = React.createClass({
    handleChange: function (e) {
        this.props.onChange(e);
      },
    render: function() {
         var options = this.props.options.map(function(opt, i){
          return <option key={i} value={opt.value} label={opt.label}>{opt.label}</option>;
        }, this);
          return (
            <b.Input type="select" label=''
                defaultValue={this.props.defaultValue}
                multiple={this.props.multiple}
                name={this.props.name} style={this.props.style}
                onChange={this.handleChange}
                >
                {options}
            </b.Input>
          );
    }
  });
```
mapでArrayに入れ、それをrenderで展開する方法です。