React Storybook入門：コンポーネントカタログがさくさく作れちゃうかもしれないオシャレサンドボックス環境

React Storybook は React をコンポーネント単位でサンドボックスで開発できる開発環境です。

- [Introducing React Storybook — KADIRA VOICE — Medium](https://voice.kadira.io/introducing-react-storybook-ec27f28de1e2)
- [kadirahq/react-storybook: Isolate your React UI Component development from the main app](https://github.com/kadirahq/react-storybook)


React Storybookの特徴って
---

実際のReact Componentをサンドボックス内で呼び出してレンダリングします。よってコンポーネントの色々な状態（0件とか新着ありとか）も少ないコードでカタログ化が可能。また、actionというAPIを使ってコンポーネントのイベントをキャッチしてログに流してくれたりもします。
状態込みのスタイルガイドって非常にメンテナンスが面倒なので、これ使えたらかなり革新的じゃないかなぁ……

![React Storybook起動画面](https://qiita-image-store.s3.amazonaws.com/0/52756/3b62b384-675f-6548-4301-aae5f0c729b6.png "左：ストーリー一覧、右上：サンドボックス、右下：アクションロガー")


- `iframe` を利用したサンドボックス内にコンポーネントを隔離します
- モジュールは自動でリロードされます（関数型のステートレスなモジュールも含め）
- `Redux`や`Relay`、`Meteor`などを使っていても利用可能
- さまざまなタイプのCSS（）に対応しています
- 早くてかっこいいUI
- プロジェクト内で動作するので、`npm`や`babel`などアプリの環境を使いまわせます
- 静的ファイルのサービングも可能
- `Webpack`をカスタマイズしたりプラグインを追加したりと拡張が可能


デモを触ってみる
---

```shell
git clone https://github.com/kadira-samples/react-storybook-demo
npm install
npm run storybook
```

`Redux`で実装された TODOアプリ のデモになります。
React Storybookが無事に起動できたら`http://localhost:9001`にアクセスしてみましょう。


インストール
---

では、実際に自分のReactプロジェクトにインストールしてみましょう。

1. `@kadira/storybook`をインストール
2. 必要なモジュールをインストール
3. `package.json`に実行用スクリプトを追加

```shell
npm i --save-dev @kadira/storybook
npm i --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 react react-dom stack-source-map webpack webpack-hot-middleware
```

```json:package.json
{
  ...
  "scripts": {
    "storybook": "start-storybook -p 9001"
  }
  ...
}
```

使ってみる
---

### ストーリーを作る (`components/stories/story.js`)

まずはstoryを作ります。
どこに作っても良いのですが、基本的にコンポーネントと1:1で対応するものなので、`components/stories/`みたいなフォルダを作って、そこに入れていくのが推奨されています。
サンプルドキュメントからボタン2種類が登録されたストーリーを作ってみましょう。

```js:components/stories/button.js
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';

storiesOf('Button', module)
  .add('with a text', () => (
    <button>My First Button</button>
  ))
  .add('with no text', () => (
    <button></button>
  ));
```

`storiesOf`で指定するのがコンポーネントですね。さらにチェインして`.add()`でモジュールの状態を追加しておきます。
例えば、`validateField`というコンポーネントに対して、「未入力」「not valid」「valid」の3種類を`.add()`するみたいな感じです。


### Storyを読み込む (`.storybook/config.js`)

これで起動しようとしても`.storybook/config.js`を作れと言われるので、ドキュメントを参考に作ります。

```js:.storybook/config.js
import { configure } from '@kadira/storybook';
import 'css/style.css';

function loadStories() {
  require('../components/stories/button');
}

configure(loadStories, module);
```

`loadStories()`内で先ほど作ったストーリーをインポートします。たくさんコンポーネントがある場合は並べてもいいし、フォルダまとめて登録する方法なんかもドキュメントに書いてあります。
スタイルシートを設定する場合は、`import`で可能なのですが、Reactには色々なCSSの流儀があるので詳細は[ドキュメント](https://github.com/kadirahq/react-storybook/blob/master/docs/setting-up-for-css.md)を読みましょう。


### 起動する

```shell
npm run storybook
```

やっとこれで準備できました。
`http://localhost:9001`にアクセスできて左側に`button`が表示されていればOK。


### イベントをキャッチする (`action()`)

Storybookにはさらにコンポーネントのイベントをキャッチする機能が搭載されています。先ほどの`button.js`を以下のように書き換えてみましょう。

```js:components/stories/button.js
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';

storiesOf('Button', module)
  .add('with a text', () => (
    <button onClick={action('click')}>My First Button</button>
  ))
  .add('with no text', () => (
    <button></button>
  ));
```

テキスト付きボタンの方を押すと、下の"ACTION LOGGER"にログが流れたと思います。

### 自作のコンポーネントをストーリーに登録する

ボタンのサンプルでは自作のコンポーネントを読み込んでいませんが、普通に`import`文で読み込んで、それを使用したストーリーを`.add()`すればOKです。サンプルの TODOアプリ には4つのストーリーが登録されていますが、それぞれ特徴的になっているので参考になると思います。


エンジニアとデザイナーのコミュニケーション改善に役立つんじゃない？
---

うまくいくかは分からないですが、以下みたいな使い方すると「あれがなかった！」「これ伝え忘れた」みたいなの防げそうな予感。

1. エンジニアが必要なストーリーを書いてそれをデザイナーに渡す
1. デザイナーはそれに対して（ストーリー内で）デザイン&コーディングを行う
1. エンジニアがそのコードをコンポーネント化する
1. それ以降はこのストーリー上でデザインの変更を行う

また、状態のパターンやどんなアクションがあるかなど、ストーリーを見ると一目瞭然なので、仕様書代わりとしても機能するんじゃないかな、と思います。

最後に「こんな風にしたらうまくいくぜ」的なマントラがドキュメント中にあったので意訳しておきます。

> - コンポーネントは`props`を使ってデータを受け渡ししましょう。分割するのが楽になります
> - UIコンポーネント中にアプリに依存したコードは書かないようにしましょう
> - ストーリーはコンポーネント近くに置きましょう。`components`フォルダの中なんかは最適です
> - `Meteor`を使う場合はストーリーを`tests`フォルダの中にするか`.stories`にしないとダメです
> - ひとつのストーリーではひとつのコンポーネントに対するストーリーを書きましょう
> - ストーリーにプレフィックスをつけるならドットがオススメ（例：`storiesOf('core.Button', module)`）
> - イベントハンドラのデバッグには必ず`actions()`を使いましょう