React.js - HAML風に書く方法

#経緯

先日[ある記事](https://www.airpair.com/reactjs/posts/reactjs-a-guide-for-rails-developers)を読んでいて、少し工夫するだけでReact.jsをHAML風に書くことができることに気がついた。

#やりたいこと

React.jsを日頃よく使う[HAML](http://haml.info/)のように書きたい。

![Screenshot 2015-07-06 09.02.49.png](https://qiita-image-store.s3.amazonaws.com/0/82804/92751574-bc1d-4d66-c7b2-f971e044ff00.png)

```haml:目標
%div
  %table
    %thead
      %tr
        %th 'Name'
        %th 'Vol'
        %th 'Qty'
        %th 'Subtotal'
        %th 'Room'
        %th 'Category'
        %th 'Description'
        %th ''
    %tbody
      = render @records
```

普通にJSX + CoffeeScriptで書くと以下の様になる。＜＞を排除したい。

```coffee:
@Records = React.createClass
  #...
  render: ->
     <div>
       <table className='table table-bordered'>
         <thead>
           <tr>
             <th>Name</th>
             <th>Vol</th>
             <th>Qty</th>
             <th>Subtotal</th>
             <th>Room</th>
             <th>Category</th>
             <th>Description</th>
             <th></th>
           </tr>
         </thead>
         <tbody>
           { for record in @state.records
               <Record key={record.id} record={record}
                       handleDeleteRecord={this.deleteRecord}
                       handleEditRecord={this.updateRecord} />
           }
         </tbody>
       </table>
     </div>
```

#やりかた

###１. JSXを使用せず、CoffeeScriptで書く
JSXは選択肢として用意されているが、必要条件ではないとドキュメンテーションに書かれている。
>[JSX is optional and not required to use React.](http://facebook.github.io/react/)
>[You don't have to use JSX with React. You can just use plain JS.](http://facebook.github.io/react/docs/jsx-in-depth.html)

先ず、JSXを使用せず書くとこんな感じになる。当たり前だが、これだけで＜＞を排除可能。

```coffeescript:records-2.js.coffee

@Records = React.createClass
  #...
  render: ->
    React.DOM.div null,
      React.DOM.table
        className: 'table table-bordered'
        React.DOM.thead null,
          React.DOM.tr null,
            React.DOM.th null, 'Name'
            React.DOM.th null, 'Vol'
            React.DOM.th null, 'Qty'
            React.DOM.th null, 'Subtotal'
            React.DOM.th null, 'Room'
            React.DOM.th null, 'Category'
            React.DOM.th null, 'Description'
            React.DOM.th null, ''
        React.DOM.tbody null,
          for record in @state.records
            React.createElement Record,
              key:    record.id,
              record: record,
              handleDeleteRecord: @deleteRecord,
              handleEditRecord:   @updateRecord
```

###2. 更に`React.DOM.xxx`をローカル変数に置き換えるとHAML風になる。

```coffee:records-3.js.coffee
@Records = React.createClass
  #...
  render: ->
    div   = React.DOM.div
    table = React.DOM.table
    thead = React.DOM.thead
    tr    = React.DOM.tr
    th    = React.DOM.th
    tbody = React.DOM.tbody

    div null,
      table
        className: 'table table-bordered'
        thead
          tr null,
            th null, 'Name'
            th null, 'Vol'
            th null, 'Qty'
            th null, 'Subtotal'
            th null, 'Room'
            th null, 'Category'
            th null, 'Description'
            th null, ''
        tbody null,
          for record in @state.records
            React.createElement Record,
              key:    record.id,
              record: record,
              handleDeleteRecord: @deleteRecord,
              handleEditRecord:   @updateRecord
```
###3. `React.DOM`の部分のみをローカル変数に置き換え、以下の様に書くことも可能。

```coffee:records-4.js.coffee
R = React.DOM

@Records = React.createClass
  #...
  render: ->
    div null,
      table
        className: 'table table-bordered'
        R.thead
          R.tr null,
            R.th null, 'Name'
            R.th null, 'Vol'
            R.th null, 'Qty'
            R.th null, 'Subtotal'
            R.th null, 'Room'
            R.th null, 'Category'
            R.th null, 'Description'
            R.th null, ''
        R.tbody null,
          for record in @state.records
            React.createElement Record,
              key:    record.id,
              record: record,
              handleDeleteRecord: @deleteRecord,
              handleEditRecord:   @updateRecord
```

#資料
- http://facebook.github.io/react/docs/top-level-api.html
- https://www.airpair.com/reactjs/posts/reactjs-a-guide-for-rails-developers