【React】StoryBookをComponent Story Format（CSF）で実装してみる

# 概要
React × StoryBook でコンポーネントを表示してみます。
なおかつ、Component Story Format（CSF）というフォーマットで実装してみます。

# 背景
僕は storiesOf しか利用したことがありません。
現在は CSF を利用したやり方が推奨らしいのでお勉強してみます。

# StoryBook とは
Storybookは「UI カタログ」です。それぞれの UI コンポーネントをブラウザで手軽にチェックすることができます。
React 以外にも Vue や Angular、Svelte などにも対応しています。
オープンソースで無料のサービス（モジュール）です。

# Component Story Format（CSF）とは
Storybookでコンポーネントを記述するフォーマットです。
ESmoduleをベースに記述されており、Storybook 以外でも活用できます。﻿

storiesOf と違い「Jest や Cypress など、他ツールとも連携できる」という点がメリットです。

# storiesOf と CSF の書き方の違い
詳細な説明は割愛させていただきますが、書き方の違いはこんな感じです（ふーんくらいの理解でOKです）

### storiesOf
```jsx
import { storiesOf } from '@storybook/react';
import Button from './Button';

storiesOf('Button', module)
 .add('Primary', () => <Button type="primary" />)
```

### CSF
```jsx
import { Button } from './Button';

export const Primary = {
  component: Button,
  args: {
    type: "primary",
  },
};
```

# サンプルコード
今回作成するコードは github、codesandbox にて公開しています。
ご自由にご参照ください！
- [github](https://github.com/ikeyuki0220/react-storybook)
- [codesandbox](https://codesandbox.io/p/github/ikeyuki0220/react-storybook/main?embed=1)

# 環境準備
さぁ、それでは手を動かしていきましょう！

いつもの如く [codesandbox](https://codesandbox.io/) を使います。
今回はテンプレートとして `Storybook (React)` を使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/7e13f96a-6a6b-c927-10da-52030fcf9ea5.png)

:::note info
codesandbox の使い方が分からない方は以下の記事をご参照ください
[【CodeSandbox】基本的な使い方と機能説明～React Vueの開発環境を作る～](https://it-memo.work/codesandbox-javascript-react-vue/)
:::

# 不要なファイルを削除する
`stories` 配下のファイルをすべて削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/28f1075c-c5e8-1e0c-fd61-a093c9d0a524.png)

# ボタンコンポーネントを作成する
### 1. `src` 配下にButton.jsx と Button.css のファイルを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/c573d513-d9a0-ed0b-e8fa-a47a97d93db7.png)

### 2. Button.jsx に以下を記載する
```jsx
import "./Button.css";

export const Button = ({ label = "", backgroundColor = "" }) => {
  return (
    <a href="" className="btn" data-background-color={backgroundColor}>
      {label}
    </a>
  );
};
```

### 3. Button.css に以下を記載する
```css
.btn {
  display: block;
  text-align: center;
  vertical-align: middle;
  text-decoration: none;
  width: 120px;
  margin: auto;
  padding: 1rem 4rem;
  font-weight: bold;
  border: 2px solid #27acd9;
  background: #27acd9;
  color: #fff;
  transition: 0.5s;
}

.btn[data-background-color="red"] {
  background: #d92771;
  border: 2px solid #d92771;
}

.btn[data-background-color="yellow"] {
  background: rgb(217, 190, 39);
  border: 2px solid rgb(217, 190, 39);
}

.btn:hover {
  color: #27acd9;
  background: #fff;
}
```

# StoryBook を作成する

### 1. `stories` 配下に Button.stories.js ファイルを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/fae55d6c-c732-a3e3-7084-2d4e2bbfbac3.png)

### 2. Button.stories.js に以下を記載する
```jsx
import { Button } from "../Button";

export default {
  title: "Components/Button",
  component: Button,
  tags: ["autodocs"],
  args: {
    label: "Button",
    backgroundColor: "",
  },
  argTypes: {
    label: {
      description: "ボタンのラベル名",
      table: {
        defaultValue: {
          summary: "",
        },
        type: {
          summary: "string",
        },
      },
    },
    backgroundColor: {
      description: "ボタンの背景色",
      table: {
        defaultValue: {
          summary: "",
        },
        type: {
          summary: "string",
        },
      },
    },
  },
};

export const Default = {};

export const Red = {
  args: {
    backgroundColor: "red",
  },
};

export const Yellow = {
  args: {
    backgroundColor: "yellow",
  },
};
```

### 3. StoryBook をプレビューする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/5e14fb3c-8040-1089-79e9-afec6e802280.png)


こんな感じで表示されました。

# 解説
### 1. title
```jsx
export default {
  title: "Components/Button",
};
```
StoryBook のサイドバーでコンポーネントをグループ化または分類するためのタイトルです。
画像中の赤枠部分に該当します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/4b4f061b-413b-a617-99d3-ec5c44f4870d.png)

### 2. component
```jsx
export default {
  component: Button,
};
```
Story として表示するコンポーネントを指定します。

### 3. tags
```jsx
export default {
  tags: ["autodocs"],
};
```
コンポーネントのドキュメントを自動生成するためのタグです。
画像中の赤枠部分に該当します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/e1b9ea33-661e-3d5a-5e08-d5e12255f510.png)

### 4. args
```jsx
export default {
  args: {
    label: "Button",
    backgroundColor: "",
  },
};
```

コンポーネントに渡す Props を定義するものです。
`export default` に定義することによって、デフォルトの Props として扱います。
つまり、各 Story で `label` を省略した場合は `label: "Button"` が Props としてコンポーネントに渡されます。

### 5. argTypes
```jsx
export default {
  argTypes: {
    label: {
      description: "ボタンのラベル名",
      table: {
        defaultValue: {
          summary: "",
        },
        type: {
          summary: "string",
        },
      },
    },
    backgroundColor: {
      description: "ボタンの背景色",
      table: {
        defaultValue: {
          summary: "",
        },
        type: {
          summary: "string",
        },
      },
    },
  },
};
```

Props の説明や渡される型、初期値の設定を行うことができます。
イメージとしては JSDoc のような感じですね。

設定した値は Docs にて確認することができます（画像中の赤枠参照）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/37845275-2ff6-2b42-ba8d-25f7838706a9.png)

### 6. 各 Story の説明
今回は Story として以下を用意しました。

| Story名 | ボタンの背景色 | 
|:-----------|:-----------|
| Default     | 青      | 
| Red       | 赤        | 
| Yellow         | 黄          | 


#### Default
```jsx
export const Default = {};
```

Button コンポーネントのデフォルト表示です。
`export const ${Story名} = { ${args などの設定値} };` のようなルールで定義します。

Props を指定する場合は `{}` 内に args を指定しますが、`export default` 内で定義している `args` を使用するので特に何も記載していません。

サイドバーの「Default」を選択するとプレビューを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/01df9230-6f40-0d70-4d88-6e7e4bc49ff2.png)

#### Red
```jsx
export const Red = {
  args: {
    backgroundColor: "red",
  },
};
```

Button コンポーネントの赤色背景 ver の表示です。
サイドバーの「Red」を選択するとプレビューを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/ddc8d53b-ff73-cddd-b7a9-6ac14c23645b.png)

#### Yellow
```jsx
export const Yellow = {
  args: {
    backgroundColor: "yellow",
  },
};
```

Button コンポーネントの黄色背景 ver の表示です。
サイドバーの「Yellow」を選択するとプレビューを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806222/362e1f87-0c48-9945-c0cd-d403c2f9d2e1.png)

# 感想
storiesOf API と全然違う書き方なので最初は戸惑いました笑
慣れると割とサクサク書けました。

個人的には（慣れもあって）storiesOf の方が分かりやすい気もします…笑
ただ、これからは CSF が主流になると思うので、この流れに乗り遅れないようにコツコツと勉強していこうと思います！

今回も見てくださりありがとうございます。
また次回お会いしましょう