JavaScript
vue.js
AtomicDesign

最初に

この記事はVue.jsが最近のマイブームな若造フロントエンドエンジニアが、
コンポーネントの再利用性とイベントバケツリレーの煩雑さの間でもがき苦しみ
AtomicDesignなるものに行き当たった結果、
これをVue.jsで実現する方法を考え書き綴ったものです。

Vue.jsやVueコンポーネント、Vuex / Vue Routerとはなんぞやという部分については
適当に触れる程度にわかってる前提で話を進めます。

そもそもQiita初投稿になるので文章の読みにくさなどはこっそり指摘をください。

経緯

個人開発のアプリケーションで、SPAを作ってみようと思い至る

Vuex / Vue Routerを考えなしに導入

再利用性のなさに絶望

ページごとに必要なデータを揃えるだけの親コンポーネント作る

イベントバケツリレーに辟易

だいたいこんな感じです。
「イベントバケツリレー」と「Vuex / Vue Routerにガッチガチにコンポーネントが縛られる現象」についてはVue.js始めた人なら必ず通る道と勝手に思っています。

AtomicDesign とは?

もともとはUIデザインの手法のようです。
UI要素を、以下の5つに分類します。

  • Atoms (原子)
    • UIの最小単位。ボタンやラベルなど、「これ以上分割できない」単位。
  • Molecules (分子)
    • 複数のAtomsから構成される、単純な機能を表現する単位。
  • Organisms (有機体・生体)
    • Atoms, Molecules, あるいは他のOrganismsから成る、
      あるまとまった意味を持つような単位。ヘッダ、フッタなど。
  • Templates (テンプレート)
    • 複数のOrganismsを組み合わせワイヤーフレーム化したもの。
      ページ全体のレイアウトを整えるものと言ってもいい。
  • Pages (ページ)
    • Templatesに実際のデータ、文言などを流し込んで完成したページ。

詳しくは以下のページを参照ください。

本題

早速これらをVue.js (+ Vuex / Vue Router)の文脈に置き換えて考えてみました。

  • Atoms
    • UIの最小単位。通常のHTML要素やそれらのシンプルな拡張。
    • (ex. 型バリデーションをする<input>要素)
  • Molecules
    • 複数のAtomsから構成される、ドメイン色の薄いデータを受け取って単一の機能を実現するコンポーネント。
    • props down, events upで実現されるのが望ましい。
  • Organisms
    • Atoms/Molecules/Organismsから成る、ドメインに強く左右されるデータを取り扱うためのまとまった機能を提供するためのコンポーネント。
    • Vuexやその他ストアオブジェクトとの繋ぎこみはここで行う。
  • Templates
    • <slot></slot><router-view></router-view>を使ってページ全体のレイアウトを提供する。
    • (ex. 3つの名前付き<slot>を使った聖杯レイアウト)
  • Pages
    • ドメインの各ページに対応する。TemplatesにOrganisms/Molecules/Atomsを流し込んで実際のページを構築したり、Vuexへの初期データ読み込み(API通信など)、Vue Routerのデータ利用はここで行う。

ポイントとしてはTemplatesもまた再利用可能なものであるということです。
ページ全体のTemplateに情報やパーツを流し込んで個別のページを作り上げるのはPagesの担当です。
ドメインやストアに関わる情報はPages/Organismsに集中させ、Atoms/Molecules/Templatesは再利用可能なように構成します。
これによって、少ないイベントリレーでVuexストアを利用することが可能になると思います。

まとめ

本稿の解釈はあくまで個人的な主観、経験からくるものが強いので、
ありきたりではありますが「VuexやVue-Routerとの結合度が高い再利用を考えないコンポーネント」と「結合度の低い再利用性の高いコンポーネント」に分けることが再利用性の高いコンポーネント設計に役立つのではないかなと思います。