ReactでサクッとStorybookを導入する

#### 自分のReact PJにStorybook導入してみたいけど、なんかめんどくさそう...という方へ向けて、サクッと簡単に導入できるまでのステップを紹介します。

### 1.Storybookのインストール
まず`npx create-react-app ${React PJ名}`でReactのPJを作成、もしくは既存のReact PJを開き、以下のコマンドを叩くだけです。

```.bash
$ npx storybook init
```

このコマンドを叩くと以下のようなdirが新たに作成されます。
```
React PJ/
    ├ + .storybook/
    ├ src/
       ├ + stories/
```

このうち`.storybook`にはStorybookを動かすための基本的な設定が、`stories`ディレクトリにはサンプルのStorybook用のコンポーネントファイルが格納されます。

#### 2.フォルダ構成の設定（❎必須）
ここで、まずどんなフォルダ構成にするのかを考えましょう。
例えばデフォルトで作成された`stories`フォルダにstorybook関連のファイルだけ格納するのか、自分で`components`フォルダに格納したコンポーネント用ファイルにstorybook関連のファイルも格納するのか？

私の場合は後者にしてみました。

特にStorybookをデフォルトでインストールした状態でも動きますが、`components`フォルダにしか格納しない予定なので、storyを読み込みにいくパスを変更しておきます。

```.storybook/main.js
module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/preset-create-react-app"
  ],
  "framework": "@storybook/react",
  "core": {
    "builder": "@storybook/builder-webpack5"
  }
}
```

これを
```.storybook/main.js
module.exports = {
  "stories": [
    "../src/components/*.stories.@(js|jsx|ts|tsx)"
  ],
...
```
こうしてみました。

### 3.Storyの書き方の説明

今回は`Input`というコンポーネントを作ってみました。
コンポーネントの方は特に普通にReactでやる通りに書けばOKです。

```stories/Input.jsx
import React from 'react';
import PropTypes from "prop-types"

function Input({ 
    labelName = "", 
    labelTitle = "", 
    inputType = "text", 
    value = "", 
    width = "300", 
    borderColor = "gray"}) {
  return (
  <div style={{display: 'flex', flexWrap: 'wrap', width: width}}>
      <label 
        name={labelName} 
        style={{marginBottom: 10, width: width}}>
          {labelTitle}
      </label>
      <input type={inputType} value={value} style={{border: `1px solid ${borderColor}`}}/>
  </div>)
}

Input.propTypes = {
    labelName: PropTypes.string,
    labelTitle: PropTypes.string, 
    inputType: PropTypes.string,
    value:  PropTypes.string,
    width:  PropTypes.number, 
    borderColor: PropTypes.string,
}

export default Input

```

次に、Story用に`Button.stories.jsx`を書きます。
**基本的にコンポーネントファイル+コンポーネント用のstoryファイルをセットで書きます。**
またstory用のファイルは **コンポーネント名.stories.js(x)** というファイル名にする必要があります。

```stories/Input.stories.jsx
import React from 'react';
import Input from './Input';

// まず、以下export default内にコンポーネントの基本情報を書きます。
// 1. title: ここに書いた内容がStorybook画面でフォルダ構成として表示されます。例えば以下の場合、`Example/Button`とした場合Exampleというフォルダ（まとまり）以下にButtonというコンポーネントが表示されます。
// 2. component: ここで設定するコンポーネント名
// 3. argTypes: これは特に必須ではないのですが、コンポーネントファイルに書いたPropTypesや、デフォルト値を上書きすることができます。

export default {
  title: "Input",
  component: Input,
  argTypes: {
      width: {type: 'number', defaultValue: 500}
  }
}

// Templateとして、ここにどんなパターンのコンポーネントを書くのか、その元となるテンプレートを書きます。
const Template = ({ ...args }) => (
  <Input {...args}/>
)

// 以下、Templateを使って、色々なパターンのPropsなどを渡したスタイルなどを定義できます。
// ここではわかりやすいように、とりあえずtextのインプットと、パスワード用のインプットを作ってみました。
export const TextInput = Template.bind({})
TextInput.args = {
    labelName: "", 
    labelTitle: "Title",
    inputType: "text",
    value: "",
    flex: true,
    borderColor: 'pink'
}

export const PasswordInput = Template.bind({})
PasswordInput.args = {
    labelName: "", 
    labelTitle: "Password",
    inputType: "password",
    value: "",
    flex: true,
    borderColor: 'blue'
}

```

#### 4.Storybookを立ち上げてみる

さて、ここまで書けたら`npm run storybook`をします。
すると、`localhost:6006`にStorybookが立ち上がりました。

![sc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485150/2c567f04-9236-a472-964f-30256eb4175e.png)

下の方に`Controls`というタブが見えていますが、ここに直接値を渡すことでコンポーネントの見た目を動的に変えてみることができます。
例えば、`value`の隣のインプットに文字を入れると、コンポーネント内のInputに値が表示されます。

次に、画面上部の`Docs`タブを開きます。
すると、コンポーネントファイルのPropTypesで設定した型の設定が反映されています。

![スクリーンショット 2022-09-24 14.30.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485150/780cc26b-b12f-1f14-fec4-8c5b89fcaa22.png)

これでStorybookが簡単に設定出来ました。
次回以降は、テストなど詳しい設定についても書いていきたいと思っています。