Riot を React の文脈で理解する

Riot は React のような UI ライブラリです。

ライブラリの特徴については [公式サイトの比較](http://riotjs.com/ja/compare/) や [以前に書いた Qiita](http://qiita.com/aggre/items/928eb2bedbac6a7829c0) を参照してもらえれば伝わるかと思います。

React が DOM の複雑な操作をあくまでも JavaScript で解決しようとしているライブラリに対して、Riot はそこを HTML+α で解決するため Web Components を先取りして書けるようにしたライブラリを指向しているという点で大きな思想の違いは存在しています。

実際、Riot の issue では構文を Web Components 準拠にする変更があがったり、Shadow DOM 実装が検討されていたりと、割りと HTML の世界に近いライブラリとなっています。

その上で、ここではコードベースで、React でこう書くとき Riot はどう書くの？ という視点で比較してみます。

React の API 名に続いて Riot で書く場合のコードを記しました。

# 前提

比較対象のバージョンは次のとおりです。

- Riot v3.4.2
- React v15.5.0

Riot は v4 で内部実装の大幅な変更のほか、新たな DOM アップデート戦略への転換などのため API の変更が検討されています。 [Riot #2283](https://github.com/riot/riot/issues/2283)

React も v16 で Fiber への変更や API の変更が検討されています。 [React #8854](https://github.com/facebook/react/issues/8854)

2017~2018 年は両ライブラリとも期待度の高いアップデートが控えていますね。

## Riot のプリプロセッサ

Riot は独自のコンパイラによってコンポーネントを js に変換します。このときコンポーネントの Script, HTML, CSS すべてにおいて好みのプリプロセッサを使用できます。

ここで説明するのはあくまで Riot のデフォルトの仕様です。

Riot の気に入った部分だけ使いつつ、Script を好みの言語や仕様( 自作もできます! )にするということもできます。プリプロセッサについては [公式サイトのガイド](http://riotjs.com/ja/guide/compiler/#プリプロセッサ) を参照ください。

# ライフサイクル

コンポーネントをマウントしてアップデート、アンマウントするなどのライフライクルを比較します。

## マウント

### `constructor()`

```html
<ex>
    <p>Hello, { userName }</p>
    <script>
        this.userName = 'John'
    </script>
</ex>
```

Riot のコンポーネントはあくまでも *普通の HTML* のように記述するので、`Class` を意識しません。そのため `constructor()` で定義しておきたいことは、ただ *そこ* に書くだけです。

### `componentWillMount()`

```html
<ex>
    <script>
        this.on( 'before-mount', () => {
            // before the tag is mounted
        } )
    </script>
</ex>
```

初回のレンダリング前に実行させたい内容はコンポーネントに `before-mount` を `on` させてコールバックを渡せば OK です。

### `render()`

```html
<ex>
    <p>Hello</p>
</ex>
```

もはや API はありません。普通の HTML のように書いてください。

### `componentDidMount()`

```html
<ex>
    <script>
        this.on( 'mount', () => {
            // right after the tag is mounted on the page
        } )
    </script>
</ex>
```

`componentWillMount()` と同様の手法で、Riot では `mount` を `on` します。

### `ReactDOM.render()`

```html:html
<ex></ex>

<script>
    riot.mount( 'ex' )
</script>
```

HTML にコンポーネントをマウントするときは `riot.mount()` にコンポーネント名を渡すだけです。

### 順序

以上のライフライクルは React と同じ順序で実行されます。

つまり、以下のようなコンポーネントを実行すると:

```html
<ex>
    <p>{ console.log( 'render' ) }</p>
    <script>

        console.log( 'constructor' )

        this.on( 'before-mount', () => console.log( 'before-mount' ) )

        this.on( 'mount', () => console.log( 'mount' ) )

    </script>
</ex>
```

コンソールには以下の順序で出力されます。

```bash
constructor
before-mount
render
mount
```

`console.log( 'constructor' )` がスクリプトの最終行にあっても変わりません。

## アップデート

### `componentWillReceiveProps()`

Riot にはこれに相当するものはありません。

### `shouldComponentUpdate()`

```html
<ex>
    <script>
        shouldUpdate ( data, nextOpts ) {
            return nextOpts.message !== 'goodbye'
        }
    </script>
</ex>
```

Riot で不要なアップデートを避けるには `shouldUpdate()` を使います。

`data` には`this.update()` で更新された新しい値が渡され、`nextOpts` には新しい `opts`( React でいうところの `props` )が渡されます。

Riot には `this.state` という予約済みのプロパティがありません。`this.opts` にマウント時のオプションが渡ってくること以外は、開発者の裁量に委ねられています。

### `componentWillUpdate()`

```html
<ex>
    <script>
        this.on( 'update', () => {
            // allows recalculation of context data before the update
        } )
    </script>
</ex>
```

`update` を `on` することでアップデート直前に値の再計算など、なんらかの処理を実行できます。

### `componentDidUpdate()`

```html
<ex>
    <script>
        this.on( 'updated', () => {
            // right after the tag template is updated after an update call
        } )
    </script>
</ex>
```

アップデート直後になにか実行したいなら `updated` を `on` します。

### 順序

アップデートに関するライフライクルも React と同じ順序で呼び出されます。

つまり、以下のようなコンポーネントを実行すると:

```html
<ex>
    <p>{ console.log( 'render' ) }</p>
    <script>

        shouldUpdate ( data, nextOpts ) {
            console.log( 'shouldUpdate' )
            return true
        }

        this.on( 'update', () => console.log( 'update' ) )

        this.on( 'updated', () => console.log( 'updated' ) )

        setTimeout( () => this.update(), 10 );

    </script>
</ex>
```

コンソールには以下の順序で出力されます。

```bash
render # マウントによる出力
shouldUpdate
update
render
updated
```

## アンマウント

### `componentWillUnmount()`

```html
<ex>
    <script>
        this.on( 'before-unmount', () => {
            // before the tag is removed
        } )
    </script>
</ex>
```

`before-unmount` を `on` してアンマウント直前に何かを実行できます。

```html
<ex>
    <script>
        this.on( 'unmount', () => {
            // when the tag is removed from the page
        } )
    </script>
</ex>
```

`unmount` を `on` するとアンマウント直後に実行できます。

## その他

### `this.setState()`

```html
<ex>
    <script>
        this.update( {
            userName: 'Michael'
        } )
    </script>
</ex>
```

例えば `this.userName` という変数があるとき、`this.update()` に同じキーを持つオブジェクトを渡すことで状態の更新と再レンダリングができます。

以下のように書いても同じですが、これだと `shouldUpdate` で値を受け取れないのであまり使わないほうが良いでしょう。

```js
this.userName = 'Michael'
this.update()
```

### `forceUpdate()`

Riot にはこれに相当するものはありません。`shouldUpdate` で制御します。

### `defaultProps`

Riot にはこれに相当するものはありません。

規定値を設定する場合は、普通の JavaScript で:

```js
this.userName = opts.userName || 'name'
```

のようにすれば OK です。

# HTML

HTML の文法は React が JSX なのに対して Riot はほぼ標準の HTML に近いスタイルで記述できます。

これは比較よりもむしろ Riot のドキュメントを解説することになってしまいます。

つまり、ここには書かないでいいですね？:thinking:

[公式サイトのガイド](http://riotjs.com/ja/guide/) を見てもらうのが一番わかりやすいでしょう。

．．．とはいえ、簡単なのでよくある文法だけ書いておきますね :thumbsup:

## ループ

```html
<ex>
    <ul>
        <li each="{ person in persons }">{ person }</li>
    </ul>
    <script>
        this.persons = [ 'John', 'Michael', 'David' ]
    </script>
</ex>
```

繰り返したい要素やコンポーネント自体に `each` を書くことで、その要素が繰り返されます。

## 条件

```html
<ex>
    <p if="{ enabled }">Hello</p>
    <script>
        this.enabled = true
    </script>
</ex>
```

条件が真であるときだけマウントさせたい要素やコンポーネントに `if=XXX` の形で記述すれば OK です。

`{}` の中は普通の JavaScript なので、こんなふうに:

```html
<ex>
    <ul>
        <li each="{ person in persons }" if="{ person.length > 4 }">{ person }</li>
    </ul>
    <script>
        this.persons = [ 'John', 'Michael', 'David' ]
    </script>
</ex>
```

使うこともできますし、関数で評価することもできます。

# イベント

```html
<ex>
    <button type="button" onclick="{ click }"></button>
    <script>
        click ( e ) {
            // execute something after being clicked
        }
    </script>
</ex>
```

React と同じように `onclick` や `onchange` にバインドしたい関数を渡します。

---

こんなところですね。

あとスタイルの記述も比較したいところではありますが、ちょっと疲れてしまったので一旦ここで公開します。

また、 **誤っている箇所がありましたら編集リクエストかコメントで教えてください** :bow:

よろしくお願いします。