ワイ「何でそんな小っさいコンポーネント作ってるん？ｗ」

## とあるWeb制作会社にて
ワイ「ハスケル子ちゃん」

ハスケル子「はい」

ワイ「今日ワイは何の仕事するんやったっけ？」

ハスケル子「確か今日からは」
ハスケル子「**Nuxt.js**と**Vuetify**を使って管理画面を作る案件が始まるんじゃなかったでしたっけ？」

ワイ「おお、せやった」
ワイ「とある管理画面のフロントエンド開発をするんやったな」

ハスケル子「もうFigmaのデザイン見ましたか？」

ワイ「ヒグマ？」
ワイ「ヒグマなんて、写真でしか見たことないけど」

ハスケル子「**Figma**です」
ハスケル子「ブラウザ上でも使えるデザインツールですよ」

ワイ「ああ、そっちな」
ワイ「**Higuma**のほうね」

ハスケル子「じゃあ、さっそくデザイン見ながら」
ハスケル子「コーディングしていきましょう」

ワイ「おお、頑張っていこか！」

## デザインを見てみる

<img width="274" alt="スクリーンショット 2020-06-21 17.31.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/ef0ea65b-0e1a-f820-46b8-66dece1d986a.png">

ハスケル子「↑この**キャンセルボタン**と**OK**ボタン」
ハスケル子「いろんなページで使うみたいなので」
ハスケル子「`OkButton`と`CancelButton`て感じで」
ハスケル子「それぞれコンポーネントとして作っておきましょうか」


ワイ「ん？コンポーネント作る？」
ワイ「でも今回は、**Vuetify**っていう**コンポーネントフレームワーク**を導入してるから」
ワイ「Vuetifyの**`v-btn`**っていうコンポーネントを使えばええんちゃう？」

```vue
<v-btn>
  キャンセル
</v-btn>
<v-btn>
  OK
</v-btn>
```

ワイ「↑こんな感じや」
ワイ「あとはいくつかpropsを指定してやれば、デザイン通りの見た目になるで」


ワイ「丸いボタンやから`rounded`」
ワイ「影はいらんから`depressed`」
ワイ「長さを揃えたいから`min-width="120"`」
ワイ「大きめにしたいから`large`」
ワイ「他にも色々・・・」
ワイ「あとは、クリックイベントつけて・・・」

```vue
<v-btn
  rounded
  depressed
  min-width="120"
  large
  outlined
  @click="cancel"
>
  キャンセル
</v-btn>
<v-btn
  rounded
  depressed
  min-width="120"
  large
  color="primary"
  @click="ok"
>
  OK
</v-btn>
```

ワイ「↑こんな感じや」

ハスケル子「でも、毎回こんなにprops書いてたら」
ハスケル子「面倒くさいじゃないですか」
ハスケル子「`OkButton`と`CancelButton`ていうコンポーネント作りましょうよ」

ワイ「別に、コピペするだけやん」
ワイ「何でわざわざ、`v-btn`を1つ入れるためだけのコンポーネントを作らなあかんねん」

ハスケル子「そんなに言うなら、コンポーネント化しなくてもいいですけど・・・」

## 4時間後

ワイ「ふう、だいぶコーディングが進んだな」
ワイ「2人で100ページもできたで」

ハスケル子「私が**99ページ**で、やめ太郎さんは**1ページ**ですけどね」

ワイ「ま、まぁな」

社長「おーい」
社長「やめ太郎、ハスケル子ちゃん」

ワイ「何でっか」

社長「ちょっとデザイン変わるらしいわ」
社長「丸っぽいボタンやなくて、四角いボタンに変わるみたいや」

<img width="274" alt="スクリーンショット 2020-06-21 18.14.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/60b74955-3a93-6e6a-d946-7df7008f0cd7.png">

社長「↑こんな感じや」

ワイ「**ファッ！？**」
ワイ「もう**100ページ**もコーディングしてしまいましたが！？」

ハスケル子「（やめ太郎さんは**1ページ**・・・）」

ワイ「まあ、検索置換で`rounded`を消せばいいだけか・・・」
ワイ「`rounded`というpropsを消せば、丸みがなくなるからな」
ワイ「よっしゃ、さっそく検索置換や！」
ワイ「・・・アッ！なんかエラー出た！」

ハスケル子「なんか、消しちゃいけない`rounded`も消しちゃったみたいですね」

ワイ「ぐぬぬ」
ワイ「割とありふれた単語やから、慎重に検索置換せんとな・・・」

ハスケル子「その必要はないですよ」

ワイ「えっ・・・何で・・・」

## 実はコンポーネント作ってました

ハスケル子「実は、`OkButton`と`CancelButton`ていうコンポーネント」
ハスケル子「私が作っておきました」
ハスケル子「私がコーディングした99ページでは、そのコンポーネントを使ってます」

ワイ「そ、そうなんか」

```vue
<CancelButton @click="cancel" />
<OkButton @click="ok" />
```

ハスケル子「↑こんな感じです」

ワイ「おお、スッキリやね」

ハスケル子「`OkButton`コンポーネントの中身は↓こんな感じです」

```vue:/components/OkButton.vue
<template>
  <v-btn
    rounded
    depressed
    min-width="120"
    large
    color="primary"
    @click="$emit('click')"
  >
    OK
  </v-btn>
</template>
```

ワイ「ただ`v-btn`をラップしただけのコンポーネントな訳やね」

ハスケル子「はい」
ハスケル子「この`OkButton`コンポーネントの`rounded`を消して」
ハスケル子「`CancelButton`コンポーネントからも`rounded`を消す」
ハスケル子「たった2ファイルを編集するだけで」
ハスケル子「99ページ全てのボタンが、丸から四角に変わります」

ワイ「ほんまやん・・・！」

ハスケル子「ボタン1つだけでも、コンポーネント化しておいて良かったですね」

ワイ「ぐぬぬ」
ワイ「いや、でもコンポーネント化すると」
ワイ「それを読み込むためのコードを全ページに書かんとあかんやん？」

```js
  components: {
    CancelButton,
    OkButton
  },
```

ワイ「↑こんな感じで」

ハスケル子「書かなくても大丈夫ですよ」
ハスケル子「[**ちょっとした設定**](https://qiita.com/kitaken55/items/48ea3cdb4407bae24334)をするだけです」

ワイ「」

ハスケル子「小さいコンポーネントにだって、ちゃんと価値があるんです」
ハスケル子「やめ太郎さんの小さい脳ミソにも価値があるように」

ワイ「せやな」
ワイ「ありがとう、ハスケル子ちゃん・・・！」

## もっと小さいコンポーネントも作ってた

ハスケル子「実はこんなコンポーネントも作りました」

```vue:/components/Heading2.vue
<template>
  <h2 class="heading2">
    <slot />
  </h2>
</template>
```

ワイ「こ、これは・・・」
ワイ「実質`h2`タグだけやん」
ワイ「**何でそんな小っさいコンポーネント作ってるん？ｗ**」

ハスケル子「だって、この見出しも」
ハスケル子「ほとんど全ページで登場するパーツじゃないですか」

ワイ「いや、でも・・・」

```html
<h2 class="heading2">見出し</h2>
```

ワイ「普通に↑こう書けばいいだけやん」
ワイ「もし、さっきのボタンみたいにデザイン変更が発生したとしても」
ワイ「CSSで調整すればええだけやで」
ワイ「さすがにこのコンポーネントは**無意味**やろ・・・w」

ハスケル子「チッ」

社長「おーい」
社長「またデザイン変わったわ」
社長「見出しのデザインが、ちょっと凝った感じになったわ」
社長「でも、`h2`タグの中に`span`タグでも入れれば実現可能やろ」

ワイ「**ファッ！？**」
ワイ「全ページの`h2`タグの中に`span`入れなアカンの！？」

ハスケル子「だから必要ないですって」

```vue:/components/Heading2.vue
<template>
  <h2 class="heading2">
    <span>
      <slot />
    </span>
  </h2>
</template>
```

ハスケル子「↑こうです」
ハスケル子「さっきの`Heading2`コンポーネントの中に`span`タグを書くだけです」

ワイ「おお・・・」
ワイ「小さなパーツでもコンポーネントにしておくと、修正するときにラクなんやな・・・」

ハスケル子「はい」
ハスケル子「しかも、コンポーネント化することで」
ハスケル子「グローバルなCSSじゃなくscopedにできるじゃないですか」

ワイ「あー、せやな」
ワイ「グローバルなCSSって、修正すると予想外のところに影響が出ちゃったりするもんな」

ハスケル子「そうなんです」
ハスケル子「やめ太郎さんは**無意味**だとか言ってましたけど」
ハスケル子「この説明をする時間の方が、よっぽど・・・」

<img width="400" alt="ハスケル子「無意味です。」" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/64097551-fcf0-0eff-f18a-fd0adddf40c5.jpeg">

ワイ「あ、あんまりいじめんといてや・・・」

**〜おしまい〜**

## まとめ
- かなり小さいパーツでもコンポーネント化しておくことで、修正コストを削減できた。
- コンポーネント化すると、CSSもグローバルじゃなくできるから（scoped）影響範囲がコントロールできて良いよね。


## さらに
- `OkButton`と`CancelButton`のpropsがほとんど共通なので、まずは`BaseButton`というコンポーネントを作って、それを元に2つのコンポーネントを作るとなお良し。
- ベースコンポーネント・基底コンポーネントってやつですね。
- `v-bind="$attrs"`を使って、親から受け取ったpropsを全て`v-btn`に渡すようにしておくと「ここだけちょっと違うprops渡したい！」ってときにも対応できるで！

## 前にTwitterでアンケートしたときの結果

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">&lt;h2 class=&quot;common-title&quot;&gt;見出し&lt;/h2&gt;<br><br>↑これくらいでもコンポーネントって作る派？<br>それとも、これくらいならクラス名つけてcommon.scssにスタイル書く派？</p>&mdash; 無職やめ太郎（本名） (@Yametaro1983) <a href="https://twitter.com/Yametaro1983/status/1259723928307593216?ref_src=twsrc%5Etfw">May 11, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

私も以前は「小さいコンポーネントって要るの？」派でしたが、最近は小さくても作ってもいいかなって思ってます。