ReactをCoffeeScript2で書くためのアレやソレ

ReactチュートリアルをCoffeeScriptで書こうとして四苦八苦、試行錯誤~~した~~している記録

# 開発環境
まずは、[ここ](https://github.com/reactjs/react-tutorial)から、Reactチュートリアルをクローンして、 **react-tutorial** ディレクトリに入ります。

``` bash
$ git clone https://github.com/reactjs/react-tutorial.git
$ cd react-tutorial
```
そして、必要なパッケージをインストールします。

```bash
$ npm i --save coffee-react
$ npm i --save node-dev
```
node.jsと、npmは最新版にしておいてくださいね。
あと、 **./node_modules/.bin** にPATHを通しておくと便利です（というか通ってないと動きません）。
デバッグ用のnodeモジュールも入れておきました（後で使います）。
そして、別ターミナルでコンパイル監視とアプリケーションサーバーを起動します。

```bash
$ cjsx -wc public/scripts

監視モードに入ると、そのコンソールが使えなくなるので、別コンソールで、

$ node-dev server.js
```
さらに別のコンソールで **react-tutorial/public/index.html** を開き、サンプルの削除と、スクリプトの種類を変更します。

```coffeescript
    <script type="text/babel" src="scripts/example.js"></script>
    <script type="text/babel">
```
の、 **example.js** の行を削除（いきなりチュートリアルをやるため）。
そして、その下の**script**行を、

```coffeescript
    <script type="text/cjsx">
```
と修正。
JSXのCoffeeScript版で記述することを高らかに宣言します。
本来であれば、これで、 **script**　タグの間にCJSXをゴリゴリ書いていくとReactアプリケーションが作れます。
…と言いたいところですが、いろいろハマリどころが多いので書いていきます。

# ReactをCoffeeScriptで書くということ
そもそもReactはJSXというシンタックスシュガーを用いて記述しますが、それをこれまたシンタックスシュガーであるCoffeeScriptで書こうというのがそもそも間違いの始まり。

Reactチュートリアルの、

```javascript
var CommentBox = React.createClass({
 render: function() {
   return {
     <div className="commentBox">
       Hello World!.
     </div>
   };
 }
});
ReacDOM.render(
  <CommentBox />,
  document.getElementById('content')
);
```

これを、CoffeeScript（正確にはCJSX）に直すと下記のようになる。

```coffeescript
CommentBox = React.createClass
  render: ->
    return <div className="commentBox">
      Hello World.
    </div>

ReactDOM.render <CommentBox />,
  document.getElementById("content")
```

ここに辿り着くまでにかなり長い旅をした（遠い目）。
これのハマリポイントとしては、まずはインデント。

```coffeescript
    return
      <div className="commentBox">
        Hello World.
      </div>
```
普通にインデントでこう書くとコンパイラに怒られる。なんでやねん。

```coffeescript
    return (
      <div className="commentBox">
        Hello World.
      </div>
    )
```
しかし、こうするとコンパイルは通ってちゃんと動く。
しかしCoffeeScript的に美しくない。
なので、最初の正解例のように、

```coffeescript
    return <div className="commentBox">
      Hello World.
    </div>
```
こうする。
これで、ちゃんとコンパイルも通って実行出来る。
**return** で始まって **div**　で終わってるのでちょっと気持ち悪いが、Reactはひとつのコンポーネントでは親要素をひとつしか返せないのでこれでヨシとする。

# 人様のチュートリアルをやってみる
こういう時は自称「初心者」の方のblogが役にたつ。ポエムだとただのメモなので環境などが推測しづらい。というわけでこの方のこれをやってみる。

[React入門チュートリアル](https://qiita.com/stivan622/items/ef4a0b9d5c5190b0e150)

これをCJSXで書いてみる。
まずは、これ

```javascript
const TodoList = () => {
  return (
    <ul>
      <li>ほげ</li>
      <li>ほげ</li>
      <li>ほげ</li>
    </ul>
  );
}

ReactDOM.render(
  <TodoList />,
  document.getElementById('content')
);
```
これを、

```coffeescript
TodoList = =>
  return <ul>
    <li>ほげ</li>
    <li>ほげ</li>
    <li>ほげ</li>
  </ul>

  ReactDOM.render <TodoList />,
    document.getElementById('content')
```
こう書いた。ハイ、察しのいい方は気づきましたね。ブラウザになにも出てこないんですね。バベってみたり、CoffeeScript2でコンパイルしてからバベってみたり、いろいろしたんですけどダメなんです。

**そうなんです、インデント間違ってました。**

これでは、最初の **render** が実行されません。
というわけで、

```coffeescript
TodoList = =>
  return <ul>
    <li>ほげ</li>
    <li>ほげ</li>
    <li>ほげ</li>
  </ul>

ReactDOM.render <TodoList />,
  document.getElementById('content')
```
こうしたらちゃんと動きました。

## 初期生成されるコンポーネントを指定する
なんか、最初にレンダリングするところで初期コンポーネントを指定するのが汎用性が低く感じられて（←汎用厨）変数で指定するようにしてみた。

```coffeescript
#============================================================================
# Todo List
#============================================================================
TodoList = =>
  return <ul>
    <li>ほげ</li>
    <li>ほげ</li>
    <li>ほげ</li>
  </ul>


#============================================================================
# Initial Component
#============================================================================
initComponent = TodoList

#============================================================================
# Display Base Component
#============================================================================
MainComponent = =>
  return React.createElement(initComponent, null)
ReactDOM.render <MainComponent />,
  document.getElementById('content')
```
いちおうコンパイルは通って動いている。「初期コンポーネントを変数に入れるのと、レンダリングするコンポーネントを指定するのは、同じ手間じゃね？」というツッコミはスルー。

………としたんですが、この後に **TodoList** に引数を渡さないといけなくなり、結局こうなりました。

```coffeescript
#============================================================================
# Todo List
#============================================================================
TodoList = =>
  return <ul>
    <li>ほげ</li>
    <li>ほげ</li>
    <li>ほげ</li>
  </ul>

#============================================================================
# Display Base Component
#============================================================================
ReactDOM.render <TodoList />,
  document.getElementById('content')
```
元に戻りました……。

# クラスを作ってみる
CoffeeScriptや、ES6の特徴である「クラス」が作れるので、クラスを作ってみます（元のチュートリアルで作ってるのでやってるだけ）。先頭に、**TodoApp** というクラスを定義します。コンストラクターで表示するメンバーを定義します。

```coffeescript
#============================================================================
# TodoApp
#============================================================================
class TodoApp extends React.Component
  constructor:->
    super()
    @state = {items: ['ほげ', 'ほげ', 'ほげ']}
```
そして、**render** メソッドを定義します。

```html
  render:->
    return <div>
      <h3>Todoアプリ</h3>
      <form>
        <input />
        <button>Add</button>
      </form>
      <TodoList items={@state.items} />
    </div>
```
フォームの下で、コンストラクターで定義した配列を **TodoList** に渡しています。
次に、**TodoList** を、渡された配列を表示するように改修します。

```coffeescript
class TodoList extends React.Component
  constructor:(props)->
    super(props)
    @state = props

  render:->
      return <ul>
        {@state.items.map (item, index) ->
          <li key={index}>{item}</li>
        }
      </ul>
```
**TodoApp** で **TodoList** を呼び出した際に、**items** というパラメータで渡している配列を、**constructor** で **props** という変数で受け取っています。**super()** を呼ぶのは決まりになってますね。そして、mutableな変数 **state** に代入しています（**state**について分からない方は**React**をググってください）。
**render**メソッドでは**constructor**で受け取った配列を**map**でループ処理しています。**@state.items**の各要素を（**item**, **index**）という二つの配列で、要素と配列番号を取り出します。それをそのまま**<li>**タグで表示しています。ループで複数の要素を表示する時に、**key**を設定しないとJSXコンパイルの時に怒られるらしいです（必ず指定しているので怒られたところを見たことがない）。
全部まとめるとこんな感じですね。

```coffeescript
#============================================================================
# TodoApp
#============================================================================
class TodoApp extends React.Component
  constructor:->
    super()
    @state = {items: ['ほげ', 'ほげ', 'ほげ']}

  render:->
    return <div>
      <h3>Todoアプリ</h3>
      <form>
        <input />
        <button>Add</button>
      </form>
      <TodoList items={@state.items} />
    </div>

#============================================================================
# Todo List
#============================================================================
class TodoList extends React.Component
  constructor:(props)->
    super(props)
    @state = props

  render:->
      return <ul>
        {@state.items.map (item, index) ->
          <li key={index}>{item}</li>
        }
      </ul>

#============================================================================
# Display Base Component
#============================================================================
ReactDOM.render <TodoApp />,
  document.getElementById('content')
```
多分動くと思います。

次は、チュートリアルにもあるように、配列を空にしてユーザーの入力されたものを追加して、それをリアルタイムで表示する、という感じに改修してみたいと思います。


----
#永遠につづく。