React と AtomicDesign - Molecule(分子)編

すべて個人的な考えです。

Atom (や Molecule)をよしなに組み合わせるための Molecule (分子)

よくフォームで例えられていたりしますね。例えばこんな構造だとします。

<SearchForm structure="top-menu" skin="standard">
  <Input structure="round" skin="standard" />
  <Button structure="round" skin="standard">検索</Button>
</SearchForm>

SearchFieldInputButtonが Atom です。OOCSS で考えてるのでstructureskinを持っています。しかし、それぞれのコンポーネントは子要素や兄弟要素との関連性をよく分かっていない要素達です。そういった要素たちのスタイルをよしなに組み合わせる為に Molecule 層で整えます。

例えばInputButtonは今の状態ではピタッとくっついている状態だとして、間にスペースを開けたいんだという場合はこんな感じにします。(ちなみに、styled-componentsです)

const Molecule = props => {
  const buttonSkin = React.useMemo(() => {
    if (props.value === '') {
      return 'disabled'
    }

    return 'enabled';
  }, [props.value]);

  return (
    <div style={{marginTop: 10}}>
      <SearchForm structure="fluid" skin="standard">
        <Input structure="round" skin="standard" value={props.value} />
        <div style={{marginLeft: 10}}>
          <Button structure="round" skin={buttonSkin}>
            検索
          </Button>
        </div>
      </SearchForm>
    </div>
  )
};

マージン用のdivでラップして空間を整えています。(これはstyleにしてますが、実際はコンポーネント化したものを使います)
この辺は人の好みはあると思いますが、個人的にはマージンは要素外の要因だと思っているのでそれぞれの Atom で持つのはちょっと...という考えだからです。ちゃんとしたデザインならstructureで持たせるのもありがと思いますが、来るデザインによってはマージンとかバラバラだしうまく使い回せない事が多いのでこうなりました。

ともかくこれでInputButtonの間には10pxのスペースができました。

Atom は要素の中に対して、Molecule は要素の外、つまりマージンや位置情報など他要素と関連し合うものをはここで設定しましょう。と考えると Template に近いものがあります。

計算済みの値を生成してもいい

例えば上記のサンプルコードのskin={buttonSkin}辺りがそれで、input用に渡した値を元にbuttonの見た目を変更しています。propsで渡した値をskinに渡せるようにしているのでアダプタ的な動きが近いかもしれません。

要素間のレイアウトを整えるものなので、それら要素間の依存する関係の値は持っても混乱は少ないと考えてます。またここでも状態を持たないので、Molecule と Atom の区別はそれほどしなくてもいいかもしれません。

Functional Component で定義

実装する際は最低でも Functional Component として定義するといいかと思います。複数の要素を扱うようになってくるのでプロパティの更新がなければ再レンダリングしないなどの制御も必要になってくるかなと思います。