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


とあるWeb制作会社にて

ワイ「ハスケル子ちゃん」

ハスケル子「はい」

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

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

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

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

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

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

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

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

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

デザインを見てみる

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

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

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

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

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

<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書いてたら」
ハスケル子「面倒くさいじゃないですか」
ハスケル子「OkButtonCancelButtonていうコンポーネント作りましょうよ」

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

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

4時間後

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

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

ワイ「ま、まぁな」

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

ワイ「何でっか」

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

社長「↑こんな感じや」

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

ハスケル子「(やめ太郎さんは1ページ・・・)」

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

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

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

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

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

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

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

ワイ「そ、そうなんか」

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

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

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

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

/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つだけでも、コンポーネント化しておいて良かったですね」

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

  components: {
    CancelButton,
    OkButton
  },

ワイ「↑こんな感じで」

ハスケル子「書かなくても大丈夫ですよ」
ハスケル子「ちょっとした設定をするだけです」

ワイ「」

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

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

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

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

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

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

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

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

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

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

ハスケル子「チッ」

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

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

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

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

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

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

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

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

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

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

〜おしまい〜

まとめ

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

さらに

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

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

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