react-bootstrapを使ってみる(Button)

# 見た目は大事
Reactの勉強のためサンプルコードを書いているけど、1990年代の個人ホームページのデザインっぽいのばかり量産しててもモチベーションが上がらない。とは言えデザインセンスもないのでBootstrapを使ってみようかと。

ところで、Reactからどうやって使うのかしら？

# react-bootstrapというのがあるらしい
サンプルではArdaを使うので、分からない場合は私の過去記事、もしくはグーグルさんに聞いてください。

では、早速インストール。

```
> npm install react-bootstrap
```

とりあえず、ボタンを並べてみよう。
![Buttons.PNG](https://qiita-image-store.s3.amazonaws.com/0/64288/c21fca33-3669-411c-db31-26b3c6eefb6d.png)
よく見かけるやつ。

react-bootstrapにはButtonというコンポーネントがあるので、それを使えばいいっぽい。

```js
// ButtonSample.jsx
import Arda from 'arda';
import {Button, ButtonToolbar} from 'react-bootstrap';

export default class ButtonSample extends Arda.Component {
    render() {
        return (
            <div>
                <h2>Buttons</h2>
                <ButtonToolbar>
                    <Button>Default</Button>
                    <Button bsStyle="primary">Primary</Button>
                    <Button bsStyle="success">Success</Button>
                    <Button bsStyle="info">Info</Button>
                    <Button bsStyle="warning">Warning</Button>
                    <Button bsStyle="danger">Danger</Button>
                    <Button bsStyle="link">Link</Button>
                </ButtonToolbar>
           </div>
        );
    }
}

```

ここでは、ButtonSampleというコンポーネントとした。Buttonの他にButtonToolbarがあるけど、これがないとボタンとボタンに隙間ができず、くっついてしまう。react-bootstrapの公式を斜め読みした限りではReactの仕様らしい。

これで綺麗なボタンが…の前にbootstrapのスタイルを読み込む必要がある。

index.htmlはこんなの。

```html
<doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Button Sample</title>
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
       <script src="bundle.js"></script>
    </head>
    <body>
        <div id="container" />
    </body>
</html>
```

んで、

```html
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
```

ここがそう。あとは作ったButtonSampleコンポーネントを使えばよいんだけど、動きがないとツマラナイのでLoadingButtonを追加してみる。これは、押したらボタンのタイトルが「Loading...」となって2秒後に元に戻るというもの。

```js
// ButtonSample.js
import Arda from 'arda';
import {Button, ButtonToolbar} from 'react-bootstrap';

export default class ButtonSample extends Arda.Component {
    render() {
        { /* プロパティを追加 */ }
        var isLoading = this.props.isLoading;

        return (
            <div>
                <h2>Buttons</h2>
                <ButtonToolbar>
                    <Button>Default</Button>
                    <Button bsStyle="primary">Primary</Button>
                    <Button bsStyle="success">Success</Button>
                    <Button bsStyle="info">Info</Button>
                    <Button bsStyle="warning">Warning</Button>
                    <Button bsStyle="danger">Danger</Button>
                    <Button bsStyle="link">Link</Button>
                </ButtonToolbar>

                { /* Loadingボタンはここ */ }
                <h2>LoadingButton</h2>
                <Button bsStyle="primary" disabled={isLoading} onClick={isLoading ? null : (e)=>this.onClick(e)}>
                    {isLoading ? 'Loading...' : 'Loading state'}
                </Button>
           </div>
        );
    }

    /* Loadingボタンが押された */
    onClick(e) {
        e.preventDefault();
        this.dispatch('LoadingButton:clicked');
    }
}
```

props.isLoadingがロード中かどうか。コンポーネントは外から渡されたデータを基に描画し、コンポーネント自身は状態管理しない。イベントが発生したら状態を管理しているところへ丸投げするだけ。

実際の処理はContextで行っている。

```js
window.React = require('react');
window.Promise = require('bluebird');
import Arda from 'arda';
import ButtonSample from './ButtonSample.jsx';

class App extends Arda.Component {
    render() {
        return (
                <div>
                    { /* 上で作ったコンポーネント */ }
                    <ButtonSample isLoading={this.props.isLoading} />
                </div>
        );
    }
}

class AppContext extends Arda.Context {

    static get component() { return App; }

    /* 状態はcontextで中央管理 */
    initState() { return { isLoading:false }; }

    /* コンポーネントに渡すプロパティ */
    expandComponentProps(props, state) { return { isLoading: state.isLoading}; }

    delegate(subscribe) {
        super.delegate();

        /* ディスパッチで投げたやつの受取先 */
        subscribe('LoadingButton:clicked', ()=> {
            // 状態をロード中にする
            this.update(()=> ({isLoading:true}));
            // 2秒後に状態を戻す
            setTimeout(()=> this.update(()=> ({isLoading:false})), 2000); 
        });
    }
}

window.addEventListener('DOMContentLoaded', ()=> {
    // document.bodyでは、react-bootstrapが動作しない 
    let router = new Arda.Router(Arda.DefaultLayout, document.getElementById('container'));
    router.pushContext(AppContext, {url:'/comments.json', pollInterval:2000});
});
```

長いので順番に。まずは、ButtonSampleへプロパティを渡しているところ。

```js
                    <ButtonSample isLoading={this.props.isLoading} />
```

このisLoadingで受け取っている。isLoadingの状態を変更しているのが次の部分。

```js
        subscribe('LoadingButton:clicked', ()=> {
            // 状態をロード中にする
            this.update(()=> ({isLoading:true}));
            // 2秒後に状態を戻す
            setTimeout(()=> this.update(()=> ({isLoading:false})), 2000); 
        });
```

LoadingButtonからディスパッチで丸投げした受取先がここ。イベントを受けたら、isLoadingをtrueにして、2秒たったらfalseにしてる。updateが呼ばれる度にContextの状態が変更され、コンポーネントへ通知及びプロパティの伝搬が発生して描画処理が行われる。

あと、Ardaでreact-bootstrapを使う上での注意点。

```js
    let router = new Arda.Router(Arda.DefaultLayout, document.getElementById('container'));
```

ここが前回のサンプルコードと変わってるね。document.bodyではなく、document.getElementById('container')にしないとダメっぽい。
※bootstrapがid='container'もしくは、'container-fluid'を要求する。

今回はここまで。次回はBootstrapのグリッドシステムあたりを。