React Storybook で変わるUI開発フロー (Redux Flavor)


# React Storybook で変わるUI開発フロー (Redux Flavor)
### SPAを考える会 (D3勉強会 2016.10.06)
### by @kitaly (twitter: @kita_ly)

----------------------------------------------------------------------------------------
## 自己紹介 @kitaly 

<img width="100" alt="twitter.com/kita_ly" src="https://qiita-image-store.s3.amazonaws.com/0/7801/7b65c381-7294-04c4-58e1-e43cbe8c04b0.jpeg">

Twitter: [@kita_ly](http://twitter.com/kita_ly)

- ソフトウェアエンジニア 
  - REST API開発 (Scala/Play)
  - SPA開発 (TypeScript, Angular.js, React.js)

- ビズリーチ [HRMOS](https://www.hrmos.co/) プロダクト開発部
  - 採用管理　(2016年6月リリース)
  - 勤怠管理, 評価管理, その他HR系サービス (Coming Soon..)

- 過去の発表資料
  - [サーバサイドエンジニアが 1年間まじめにSPAやってみた](http://www.slideshare.net/itaruxkita/db-flutedbflute2014-41928498)
  - [ビズリーチではDBFluteハンズオンやってます](http://www.slideshare.net/itaruxkita/db-flutedbflute2014-41928498)

<img width="182" alt="スクリーンショット 2016-10-05 13.16.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/76966ac9-f2cd-d10d-fc41-86b58065b7d7.png"><img width="353" alt="スクリーンショット 2016-10-05 13.16.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/2aaed52f-00ee-30f2-12bb-bf80399eb3a4.png">



----------------------------------------------------------------------------------------
# はじめに

### React / Redux / Webpack 前提の話ですが
### 他のコンポーネント志向FWなどでも、ユースケースやワークフローは応用可能だと思っています

### 新しいツールも多く、実践"未"投入な構想段階のアイディアも多いです

<br/>
### 今日紹介するコード例は大体ここにあります：
### https://github.com/k-italy/react-storybook-demo-plus

----------------------------------------------------------------------------------------
# 目次

- [導入] 動的UIの開発フローと課題
- [導入] 提案する解決策の概要
- [導入] Component as API
- [本題] Component開発環境としての Storybook
- [本題] Componentテスト環境としての Storybook
- [本題] Componentドキュメントツールとしての Storybook
- [Redux Flavour] Redux と Peudo-Local ライブラリ
- まとめ

----------------------------------------------------------------------------------------
[導入] 動的UIの開発フローと課題
## 動的UI開発の登場人物とスキルセットの違い

- ES君
  - 強み 「元々サーバーサイドで大規模アプリケーション組んでたし、EcmaScriptの最新仕様もバッチリ」
  - 弱み 「HTMLはなんとか書けるけど、CSSはちょっと無理ぽ…(´・ω・`)」

- W3C君
  - 強み 「HTML・CSS・JQueryなら爆速開発まかせろ」
  - 弱み 「複雑なアプリケーションは経験無いな。Immutable/Reactive/MVCとかよくわからん」

- REST君
  - （サーバーサイドの Rest API 開発してる人。今日はあんまり登場しない）


----------------------------------------------------------------------------------------
[導入] 動的UIの開発フローと課題
## HTML納品スタイル

0. マークアップエンジニアがHTML納品
0. アプリケーションエンジニアがテンプレートに書き直しアプリに組み込む流れ

- HTMLがデータ構造とか条件分岐を考慮しきれてなかったりする
  - HTML納品し直してもらうキャッチボール
  - アプリケーションエンジニアが限られたHTML/CSSの知識で修正

----------------------------------------------------------------------------------------
[導入] 動的UIの開発フローと課題
## ViewModel/ViewHelper納品スタイル

0. アプリケーションエンジニアがViewModel/ViewHelperを納品
0. マークアップエンジニアがHTMLテンプレートを書く
  
- 画面に必要なデータやHelperが足りないことが途中で判明したりしがち
  - ViewModel/ViewHelper の実装し直し
  - マークアップエンジニアがテンプレートのシンタックスを覚える必要（なおかつ汎用的な知識じゃなかったり）


----------------------------------------------------------------------------------------
[導入] 動的UIの開発フローと課題

### Angular とか React 使うとどうよ？

### → 何も考えなかったら同じようなことになる

----------------------------------------------------------------------------------------
[導入] 解決の道筋

### 解決策:　「お前ら黙って勉強しろ」
### → というのは乱暴な正論というやつ

----------------------------------------------------------------------------------------
[導入] 解決の道筋
## UI開発とアプリケーション開発の境界線付けをする

制御系の実装者とAPI提供者の区別をつける
- REST君： Rest API を提供する
- W3C君： Component API を提供する
- ES君： 上記を材料としてWebアプリケーションを組み立てる


<img width="450" alt="スクリーンショット 2016-10-06 12.55.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/3a99cca8-b4e8-d798-890a-12a17acbad69.png">



----------------------------------------------------------------------------------------
[導入] 解決の道筋
## 開発フロー

0. 開発者間でI/Fを握る
  - ES君とREST君が Rest API の仕様で合意
  - ES君とW3C君が Component API (後述)の仕様で合意
0. API提供者が並行で開発
  - REST君が Rest API の実装
  - W3C君が Component API の実装
0. ES君が制御系を実装
0. Webアプリケーションが完成

<img width="450" alt="スクリーンショット 2016-10-06 15.49.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/5849993c-a87e-de5b-3fc3-87d220ded07e.png">


----------------------------------------------------------------------------------------
[導入] 解決策の概要
## React/Redux アーキテクチャ上だと

<img width="490" alt="スクリーンショット 2016-10-06 12.52.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/e995a1c7-ed6f-1f4b-b1ae-0a76b843b4d7.png">
※ なお、私のプロジェクトでは Middleware部分 は Redux-Saga を使ってます

Redux-Middlewareに何を使うか、Flux系FWは何を使うか、等は差し替え可能かも
※ 今日は UI Component 側の話がメインなので詳しく話さないです

View部分も、React以外のコンポーネント志向FWに差し替え可能かも


----------------------------------------------------------------------------------------
[導入] Component as API

### Reactとその周辺ツールで可能になったことをおさらい


----------------------------------------------------------------------------------------
[導入] Component as API
## React の力

- Component as 変換器 / Component as Pure Function
  - 望ましいのは入力(Props)を受けて、出力(仮想DOM)する純粋関数
  - class でなく function を使うべき、という話ではないです
- 制御側でうまく利用しやすいよう、Component を副作用のないAPIとして提供可能

```js
// components/People.js

export default function People(props){
  const { users } = props;
  const items = users.length ? users.map(u => <li>{u.name}</li>) : <li>No Users</li>
  return (
    <ul>{ items }</ul>
  );
}
```

```js
// 利用の例

// 入力
const users = [ { name: "Taro" }, { name: "Jiro" }, ...]; 
const people = <People users={users} />;

// 出力 (イメージ)
<ul>
  <li>Taro</li>
  <li>Jiro</li>
  ...
</ul>
```

----------------------------------------------------------------------------------------
[導入] Component as API
## Redux(Flux) の力

Flux的機構により多くのComponentをStatelessにすることが可能に
（後述するが、StatefulComponentをゼロにはできないと思う）

- Container Component & Presentational Component
  - Presentational Component はUIのみに集中できる


```
// Container Component
const TodoListContainer = connect(
  (storeState) => ({ todoList: storeState.todoList }),
  (dispatch) => ({
    onTodoComplete: (todoId) dispatch({ type: 'TODO_COMPLETE', payload: todoId })
  })
)(TodoList)


// Presentational Component
function TodoList(props){
  const { todoList } = props;
  return (
    <ul>...</ul>
  );
}
```

----------------------------------------------------------------------------------------
[導入] Component as API
## CSS-Modules & Webpack

- CSS-Modules: CSSにローカルスコープを(擬似的に)もたらす仕組み
- Webpack: JSファイルからCSSや画像ファイルを require/import できる仕組み

これらによって Component の利用方法(I/F仕様)がシンプルになる
  - (Before) ```<Hoge/>``` を正しい見た目にするには、 hogeWrapper というクラスを付与して…
  - (After) ```<Hoge/>``` とさえ書けば Hoge 内部で閉じたCSS定義が正しい見た目にしてくれる
  
```
import * as styles from './TodoItem.scss';

function TodoItem(props){
  return (
    <div className={styles.todoItem} />
      ...
    </div>
  );
}
```


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook

### 「でも、アプリケーションに組み込まずにどうやって開発すんの？？？」


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
## React Storybook 概要

<img width="300" alt="react-storybook" src="https://qiita-image-store.s3.amazonaws.com/0/7801/d27fd97b-52bf-2e8a-ecb0-f7f7ff4ca394.png">

> React Storybook is a UI development environment for your React components. With it, you can visualize different states of your UI components and develop them interactively.
> It runs outside of your app. So you can develop UI components in isolation without worrying about app specific dependencies and requirements.
> (https://getstorybook.io/docs)

公式ドキュメント: https://getstorybook.io/

※　React/Webpack 環境を前提のツールだと思われる

----------------------------------------------------------------------------------------
[本題] Component開発環境としての React Storybook
# React Storybook 始め方 (詳しくは公式ドキュメントまで)

#### [Quick Start] (https://getstorybook.io/docs/basics/quick-start-guide)

```js
npm i -g getstorybook
cd my-react-app
getstorybook
```

create-react-app で作ったプロジェクトなら簡単にいけるっぽいが、独自にビルド組んでる場合は？


#### [Slow Start](https://getstorybook.io/docs/basics/slow-start-guide)

自分がStorybook導入した時(v1.36.0)はこれしかなかった

- ``` npm i -D @kadira/storybook ```
- 設定ファイルをゴニョゴニョ書く


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
## React Storybook の基本的な使い方

まずコンポーネント自体の実装する (前述のPeopleと同じ)

```js
// components/People.js

import React from 'react';

export default function People(props){
  const { users } = props;
  const items = users.length ? users.map(u => <li>{u.name}</li>) : <li>No Users</li>
  return (
    <ul>{ items }</ul>
  );
}
```

Storyを実装する

```js
// components/stories/People.js

import React from 'react';
import People from '../People';
import { storiesOf } from '@kadira/storybook';

storiesOf('People', module)
  .add('with non-empty list', () => {
    const users = [ { name: 'Taro' }, { name: 'Jiro' } ];
    return (
      <People users={users} />
    );
  });
```

----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
## React Storybook の基本的な使い方

コマンド実行すると、何かビルドが走ってWebサーバー立ち上がる

```shell-session
$ npm run storybook 

// package.json 内はこんな感じ
// "scripts": {　"storybook": "start-storybook -p 9001"　}
```

localhost:9001 にアクセスすると、Storybookが表示される

<img width="442" alt="スクリーンショット 2016-10-05 18.03.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/c7983029-d8e2-0ebd-b574-86e5695e6011.png">


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
# React Storybook の基本的な使い方

当然ですが、Componentが受け取るPropsは色々ある。
> ... you can visualize different states of your UI components and develop them interactively.
> https://getstorybook.io/docs

前述のPeopleコンポーネントの場合、空配列が渡された場合も動作確認したい。

```js
// 前述の　　People.js から抜粋
...
const items = users.length ? users.map(u => <li>{u.name}</li>) : <li>No Users</li>
...
```

空配列の場合のStoryも追加する

```js
// components/stories/People.js

storiesOf('People', module)
  .add('with non-empty list', () => {
    ...
  })
　　　　/* ここから追記 */
  .add('with empty list', () => {
    const users = [];
    return (
      <People users={users} />
    );
  });
```

[Webpack の HMR](https://webpack.github.io/docs/hot-module-replacement.html) のパワーで、コードを修正するとページのリフレッシュ無しに画面が更新される


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
# React Storybook の基本的な使い方

<img width="605" alt="スクリーンショット 2016-10-05 18.10.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/eda04d45-df73-3c3c-4f23-e39338442ac4.png">


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
# Add-Ons 

Storybook に追加機能をもたらすExtensionの機構。
デフォルトで linkTo/action などが提供されている。


----------------------------------------------------------------------------------------
[本題] Component開発環境としての Storybook
# linkTo add-on

```js
// components/stories/TodoItem.js

storiesOf('TodoItem')
  .add('completed', () => (
    <TodoItem onClick={linkTo('TodoItem', 'not completed')} />
  ))
  .add('not completed', () => (
    <TodoItem onClick={linkTo('TodoItem', 'completed')} />
  ));
```


<img width="597" alt="スクリーンショット 2016-10-05 18.29.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/5e28225a-4c18-6274-e927-cba62b11280c.png">
クリックすると Story間を移動できる
<img width="597" alt="スクリーンショット 2016-10-05 18.29.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/442607f7-ce52-fef1-1b79-ea2c17d5b60d.png">

ユーザのインタラクションに反応してStory間を遷移、状態遷移しているかのように見せられる。


----------------------------------------------------------------------------------------
[本題] Component開発環境としての React Storybook
# action add-on

ユーザのインタラクションをLoggingしてくれる

```js
add('xxx', () => (
  <TodoFooter onClick={action('onClearCompleted')} />
));
```

<img width="636" alt="スクリーンショット 2016-10-05 18.25.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/ecf54968-eae9-b406-74e4-d79e9ea36771.png">


----------------------------------------------------------------------------------------
[本題] Component開発環境としての React Storybook
# Decorators

ファイル単位もしくは全ファイルで共通的に、Storyを囲う要素を差し込める。

- Storyをセンタリング表示する
- Storyの見た目が白系なので、わかりやすいように黒背景の上に載せるようにする
- Redux を動かす (後述)

```js
const CenterDecorator = (story) => (
  <div style={{ textAlign: "center" }}>
    {story()}
  </div>
);

storiesOf('Hoge', module)
  .addDecorator(CenterDecorator)
  .add('with text', () => (
    <Hoge />
  ))
```


----------------------------------------------------------------------------------------
[本題] Component開発環境としての React Storybook
# Head.html

head.html というファイルを定義しておくと、グローバルに適用したいCSSファイルやFontファイルをStobybook全体で読み込める。


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook

### API提供するなら、ちゃんとテストされたものを提供したい！
### でも、こういうやつは相当クリティカルなものじゃなきゃメンテナンスできる気がしない…

<img width="453" alt="スクリーンショット 2016-10-05 19.08.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/07fa16bd-ed5c-8a80-9fd8-02a210faba63.png">
https://github.com/airbnb/enzyme

----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook

## [Storyshots](https://github.com/kadirahq/storyshots) で Structural Testing しよう

> Snapshot testing is a way to test your UI component without writing actual test cases.
> https://voice.kadira.io/snapshot-testing-in-react-storybook-43b3b71cec4f#.ndvrs9qmy

テストケース書かずに　UI　Component　をテストできる？


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# Structural Testing (Snapshot Testing) とは

> With Snapshot testing, we keep a file copy of the structure of UI components. Think of it like a set of HTML sources.

> Then, after we've completed any UI changes, we compare new snapshots with the snapshots that we kept in the file.

> If things are not the same, we can do two things:

> We can consider new snapshots that show the current state, and then update them as new snapshots.
> We can find the root cause for the change and fix our code.
> https://getstorybook.io/docs/testing/structural-testing


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# Storyshots

- https://github.com/kadirahq/storyshots
- 内部的には Jest の Snapshot Testing 機能を利用している模様
- 2016年9月にリリースされたばかり！（この発表のネタ考えてる時に見つけた）


### インストール

```
// Storybook の 2.17.0 以上が必要なので 古いVersionのStorybook をアップデートする
$ npm i -D @kadira/storybook@2.17.0 

$ npm i -D @kadira/storyshots
```

package.json に script 追加

```
"scripts": {
  "test-storybook": "storyshots"
}
```

----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook

# Storyshots の使い方

```shell-session
$ npm run test-storybook
```

<img width="597" alt="スクリーンショット 2016-10-05 19.21.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/8c6e67b4-50a7-7704-70c1-46a51980ee38.png">

Snapshotファイルが追加される。これを ``` git commit ``` しておく。

<img width="232" alt="スクリーンショット 2016-10-05 19.22.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/9fe1a02f-0ec6-4bb0-810c-ff5ad19ee1d8.png">


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# 既存のComponentに変更が入ったら

<img width="823" alt="スクリーンショット 2016-10-05 19.26.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/d560d057-abd2-cf47-09f9-1ddf4c9667e5.png">

----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# 既存のComponentに変更が入ったら

再度 storyshots を実行

```
$ npm run test-storybook
```

前回までのSnapshotとの差分をチェックします。当然差分が検知され結果はエラーに。
<img width="305" alt="スクリーンショット 2016-10-05 19.27.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/72814105-5323-a8ea-ee3b-0b7c63c3dbf2.png">

修正対象のコンポーネント自体に加え、それに依存している他のコンポーネントのStoryが意図せず変更されても気づける。
気づいたら、実際にそのStoryを目視でチェックしにいけば良い。


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# 既存のComponentに変更が入ったら

全ての差分が問題ないことが確認できたら、Snapshot更新

```
$ npm run test-storybook -- -u
```

1Storyずつインタラクティブに判定していく場合はこちら

```
$ npm run test-storybook -- -i

(差分表示)
Update snapshot? (Y/n) 
```

※ 通常の単体テストと異なりコマンド一つでテストをパスするようになるので、ノールックで更新しない最低限の倫理が必要。

もし、ローカル環境でのSnapshotの差分チェックを怠っていたら、Pull Requestをフックに自動テスト→エラーとすることも可能。


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# 実際のDOMのスナップショットを保持しているわけではないので注意

```
// .storybook/__snapshots__/TodoItem.snap

...

<label
  onDoubleClick={[Function bound handleDoubleClick]}>
  Hello Todo
</label>
<button
  className="destroy"
  onClick={[Function onClick]} />

...
```

出力されるVirtualDOMの構造が変わらなければ、CSS定義だけが変わってる場合などは気づけない。
CSS-Modulesなどをうまく利用し、そもそも副作用の少ないComponent開発を頑張る必要がある。
また、後述する CSS/Style Tesing も検討する。


----------------------------------------------------------------------------------------
[本題] Componentテスト環境としての Storybook
# 他のComponentテスト手法

### Interaction Testing
[Enzyme](https://github.com/airbnb/enzyme)などを利用し、実際にユーザがクリックしたりタイプして状態変化した結果までテストする

### CSS/Style Testing
実際にDOMのレンダリングまで行った結果のスナップショットを保持し差分検知する。
StorybookではStoryごとにURLが発行される。
BackstopJSやGeminiなどのCSS/Style TesingツールにそのURLを渡すことで実現可能（らしい

```
http://localhost:9001/?selectedKind=People&selectedStory=with
```


----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook

### 実装もテストもアプリケーションから切り離された環境でできるようになった
### これでドキュメントも作れたら嬉しい

- Component API の利用者である ES君や他のW3C君向けの APIドキュメント
- 他のW3C君向けのスタイルガイド
- デザイナや企画職の人に確認してもらう成果物（特に開発環境が無い人達）


----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook
# Storybookを静的サイトにする

react-storybook が内包している ``` build-storybook ``` コマンドを利用する

``` npm run ``` できるように package.json に追加

```js
// c: 設定ファイルのディレクトリ o: 生成したファイルの出力先ディレクトリ
"scripts": {
    "build-storybook": "build-storybook -c .storybook -o .out"
}
```

実行すると、 .out ディレクトリ配下に html/js ファイル等が出力される

```
$ npm run build-storybook
```

<img width="249" alt="スクリーンショット 2016-10-06 10.30.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/73cd3067-3429-9006-f671-2cb48eb7638a.png">

これをCIツールなど利用して、任意のサーバーにデプロイするようにしておけば、デザイナや企画の人など開発環境が無い人達でもさくっと確認可能

(手元でサクッと試したいなら、下記のような感じ)

```
$ cd .out
$ python -m SimpleHTTPServer
```

----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook

### ただ、APIドキュメントやスタイルガイドと呼ぶには不十分

<img width="868" alt="スクリーンショット 2016-10-06 10.34.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/fe69eb3e-4ad9-f9a8-d612-30302b7bcad4.png">


----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook
# addon-infoでAPIドキュメントっぽくする

インストール方法は割愛（詳しくは[リポジトリ](https://github.com/kadirahq/react-storybook-addon-info)を参照）

addWithInfo メソッドを使って、第二引数部分に任意のテキストをMarkdownで記述する。

```
storiesOf('Header', module)
  .addWithInfo(
    'default view',

    /* ↓↓↓↓↓↓↓↓↓↓↓↓ */
    `
    これはTodoアプリのHeaderですよ。
    Props:
      - addTodo: (todo: string) => void
        
    利用例:  
    \`\`\`jsx
    const addTodo = (todo) => dispatch({ type: 'ADD_TODO', payload: todo });
    <Header addTodo={addTodo} />
    \`\`\`
    `,
    /* ↑↑↑↑↑↑↑↑↑↑↑↑ */

    () => {
      return (
        <div className="todoapp">
          <Header addTodo={action('Add Todo')}/>
        </div>
      );
  });
```


----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook
# addon-infoでAPIドキュメント化

Storybook上に入力したMarkdownが表示される。<br/>
さらに Story のソースコードや、PropTypesの定義を自動でドキュメントに載せてくれるので、
Componentの利用コード例を自分で書く手間が省けそう。

<img width="400" alt="スクリーンショット 2016-10-06 10.49.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/901fcc82-f0a7-78e2-e8f2-cdba1f7af4af.png">

※ 自分で書くマークダウンに関しては、シンタックスハイライト未対応っぽい。
※ ドキュメント部分が前述のStoryshotsのSnapshotファイルに含まれてしまい test-storybook で差分検知されてしまう


----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook
# addon-notes 

インストール方法は割愛（詳しくは[リポジトリ](https://github.com/kadirahq/storybook-addon-notes)を参照）

WithNotes コンポーネントを利用して、ノートを記載。

```
import { WithNotes } from '@kadira/storybook-addon-notes';

...

  return (
    <WithNotes notes={'左側の丸をクリックしたら完了・非完了状態が切り替わるよ'}>
      <div className="todoapp">
        <div className="todo-list">
          <TodoItem
            todo={todo}
            editTodo={action('editTodo')}
            deleteTodo={action('deleteTodo')}
            completeTodo={linkTo('TodoItem', linkOnClick)}/>
        </div>
      </div>
    </WithNotes>
  );
```

<img width="300" alt="スクリーンショット 2016-10-06 10.59.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/f1f5760b-972e-8015-9308-7b42b64505c7.png">



----------------------------------------------------------------------------------------
[本題] ドキュメント生成ツールとしての Storybook
# その他ドキュメント系ツール

- [Storybook Deployer](https://github.com/kadirahq/storybook-deployer) 
  - GitHub Pages にコマンド一発でデプロイ可能（今後他のホスティングサービスにも対応予定？）

- [Storybook.io](https://storybooks.io/) （有償サービス）
  - Storybookのホスティング環境を提供
  - Pull Request 毎に Storybook を自動デプロイ
  - PRに対応するStorybook上にコメントなどして、レビュープロセスを効率化できるっぽい


----------------------------------------------------------------------------------------

### 気づけばStorybookの内容ばかりになってしまいました
（それぐらい、個人的に考えていたUI開発のあり方にドンピシャなソリューションを提供してくれてる）

### 活発に機能追加をやってるようなので最新情報をキャッチアップしたい方は：
- [Newsletter](http://tinyletter.com/storybooks) 登録 
- [Slack Team](https://storybooks-slackin.herokuapp.com/) に参加


----------------------------------------------------------------------------------------
# [再掲] Storybook で Component開発の独立化

<img width="450" alt="スクリーンショット 2016-10-06 12.55.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/3a99cca8-b4e8-d798-890a-12a17acbad69.png">

<img width="394" alt="スクリーンショット 2016-10-06 15.54.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/a96daa63-4321-b3ef-8934-9eb7425377de.png">


----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# 「本当に全て Stateless Component にすべきか？ できるか？」

### → 無理ですし、バランス感が必要だと思う
### → isMenuOpen 程度の状態管理まで分業したくない

例えば下記のような場合は Component 側で完結したい：
- 選択中のタブとか、ちょっとした閉じ開きの状態
- フォームのバリデーション等、実際に触ってみないとイマイチ動作確認にならない

同時に、Reduxの　"Single Source of Truth" の概念やタイムトラベルはなるだけ殺したくない。


----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# Pseudo Local系のライブラリ

<img width="600" alt="スクリーンショット 2016-10-06 15.50.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/7801/0a8fb2f1-b94b-4ce9-54e8-48039f3ede77.png">


https://github.com/reactjs/redux/issues/159


----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# [Redux-UI](https://github.com/tonyhb/redux-ui)

選択中のタブとか、閉じ開きのフラグのようなComponentのLocalな状態で良さげなものに利用。
状態を持たない Presentational Component を実現しつつ、reducer をイチイチ記述必要が無い。(内部的に redux-ui が state管理してくれる)

```
// containers/ToggleParagraphContainer.js

import ui from 'redux-ui';

const ToggleParagraphContainer = ui({ 
  state: { isOpen: true }
})(ToggleParagraph)
```

```
// components/ToggleParagraph.js
function ToggleParagraph({ ui, updateUI }){
  const onClick = () => updateUI({ isOpen: true })
  return (
    <div>
      <button>{ui.isOpen ? 'Close' : 'Open' }</button>
      { ui.isOpen && <p>Storybook 最高！</p> }
    </div>  
  );
}
```

----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# [Redux-Form](https://github.com/erikras/redux-form)

基本的に redux-ui と同じような発想。
Form の入力やバリデーションに特化している。

```
import form, {Field} from 'redux-form'; 

const UserEditFormContainer = form({ 
  form: 'userEditForm',
  initialValues: { userName: 'kitaly' },
  validate: validateFn,
  onSubmit: onSubmitFn
})()

function UserEditForm(props){
  return (
    <form>
      <Field name="userName" component={UserNameInput} />
      <input type="submit" value="更新"/>
    </form>  
  );
}

function UserNameInput(props){
  return (
    <p>
      <input type="text" {...props.input} />
      {props.meta.error && <p>{props.meta.error}</p>
    </p>
  );
}
```


----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# Redux-UI/Redux-Form と Storybook 

これで状態管理をReduxに任せつつ、コンポーネント開発側だけで完結できる。

```
// .storybook/config.js

import {reducer as uiReducer } from 'redux-ui';

setAddon({
  addWithRedux(storyName, storyFn) {

    const store = createStore(
      combineReducers({
        form: formReducer,
        ui: uiReducer
      }),
      {}
    );

    this.add(storyName, (context) => (
      <Provider store={store}>
        {storyFn(context)}
      </Provider>
    ));
  }
});
```

```
// containers/stories/DropdownMenuContainer.js

storiesOf('DropdownMenuContainer', module)
  .addWithRedux('normal', () => (
    <DropdownMenuContainer />
  ));
```


----------------------------------------------------------------------------------------
[脱線] Redux と Stateless Component
# Pseudo Local 系ライブラリの注意

### 不用意に汎用的な Component まで Redux依存になっていくのも好ましくない
### → 適宜 React標準の setState を利用するなどバランス間を持って使い分ける

### また Stateful な Storyは、前述の Structural Testing ではカバーしきれなくなる
### → Container Component のStoryで目視で動作確認しつつ、Presentational Component についても色々なケースのStoryを作る
### → Enzymeなどを利用して Interaction Testing を実施する


----------------------------------------------------------------------------------------
# [まとめ] 感想

- Storybook 素敵すぎる
  - 気づいたらほとんどStorybookのドキュメントで書いてあることばかりになった…orz
  - 苦でない人は[公式ドキュメント](https://getstorybook.io/)やDemoプロジェクトを見ましょう
- 分業とは言ったものの、この体制をつくるためにES君とW3C君のハイブリッド人材は１人は必要かも
- W3C君はAPIを使う側から提供する側へ、I/F設計やテスト等を考える必要性、やはり変化無しにできるわけではない
- もちろんES君もCSS勉強しましょ

----------------------------------------------------------------------------------------
### ご清聴ありがとうございました。