📌

[React] Atomic Design

2021/11/13に公開

Atomic Designとは

Atomic Designとはデザインシステムの1つの手法である。
デザインシステムとは概念的なもので、簡単にまとめるとシステム内のデザインに一貫性を持たせるためのシステムである。
React ApplicationだったらとりあえずMUI使ってカッコよくしよう!といった感じ。

Atomic Designは階層的にデザインシステムを構築していくもので、基本の構成は以下
Atoms - Molecules - Organisms - Templates - Pages
「階層的に」と聞くとAtomsから順に作成しそうだが、実際は平行に作業していく。

色々なところで散々議論されており、答えがないかもしれないが、自分の基準を以下に示す。
階層ごとの名前は参考サイトをもとに、以下とする。
Atoms - Molecules - Organisms - Ecosystems - Environments

Atoms

  • 画面表示された際の要素として最小単位
    ボタンやアイコンなど。アイコンとラベルの組み合わせもAtomsに分類
  • 機能を絞った単一部品を定義する
  • MUIならPickで使用できるPropsを絞る

Molecules

  • Atomsの組み合わせ
  • 粒度が曖昧になりがちなので個人的にMoleculesは不要

Organisms

  • 画面表示された際の機能としての単位
    ZennのTop Pageだと「Tech」一覧を表示するためのComponent はここ
  • Ecosystemsでラップし、必要な値はPropsで受け取る
  • Atoms, Moleculesを組み合わせる
  • 場合によってはEcosystemsも含む
  • e.g. DataTable.tsx

Ecosystems

  • Organismsに値、ロジックを与える
  • API呼び出しや、(Reduxの場合)Storeの値取得はここ
  • e.g. DogTable.tsx

Environments

  • Routingの責務を負う
  • 画面遷移での単位
  • 基本的にはEcosystemsを組み合わせる
  • 「***View.tsx」や「***Page.tsx」のようサフィックスを揃える
  • e.g. DogDetailView.tsx

実装例

Atomsに定義したもので機能を絞った実装の一例。
React(Typescript,MUI)を想定

Atoms

buttons, icons, inputs, labels, containersのようにサブディレクトリを作成し、1ファイル1コンポーネントで実装する。

buttonとかは基本となるものを作成し、それをもとに必要なbuttonを実装する。
例えば、基本となるBaseButtonを作成し、作成したBaseButtonを元にOkButtonを作成する。

BaseButton.tsx
import React from 'react';
import Button, { ButtonProps } from '@mui/material/Button';

export type BaseButtonProps = Pick<ButtonProps, 'onClick'> & {
  buttonLabel: string;
};

export const BaseButton: React.FC<BaseButtonProps> = (props) => {
  return (
    <Button
      variant="contained"
      onClick={props.onClick}
    >
      {props.buttonLabel}
    </Button>
  )
};
OkButton.tsx
import React from 'react';
import BaseButton, { BaseButtonProps } from '~/views/atoms/buttons/BaseButton';

export type OkButtonProps = {
  onOkButtonClick: BaseButtonProps['onClick'];
};

export const OkButton: React.FC<OkButtonProps> = (props) => {
  return (
    <BaseButton
      onClick={props.onOkButtonClick}
    >
      OK
    </BaseButton>
  )
};

Buttonにstyled-componentでspacingを与えるのも良さげ。

SpacingButton.tsx
import Button, { ButtonProps } from '@mui/material/Button';
import { spacing, SpacingProps } from '@mui/system';
import styled from 'styled-components';

export type SpacingButtonProps = SpacingProps & ButtonProps;

export const SpacingButton = styled(Button)`
  ${spacing}
`;

関連
https://zenn.dev/kosukek/articles/5972bcb65c4d3d

Discussion