Open4
Atomic Designのメモ
フロントエンド開発の悩みどころ
フロントエンド開発をしていると
- コンポーネントのpropsにどういうデータを渡すべきか
- どの粒度でコンポーネントを分けるか
が意見の分かれどころ
見た目と振る舞いを分ける
フロントエンド開発に合ったっては「見た目」と「振る舞い」を分離することで、それぞれのコンポーネントの責務が明確になり、意見が分かれにくくなる。
その結果、開発効率が上がる、テストやデバッグが簡単になる、保守性が高まる、といったメリットがある。
「見た目」をPresentational Component、「振る舞い」をContainer Component として一般的に呼ばれる。
Presentational Componentの責務
- 基本的にはpropsから渡されたデータを元にデザインを実装するだけ
- propsからデータを受け取り、それぞれのコンポーネントに割り振る
- classNameなどを指定してスタイルを適用する
- 状態を持たない
- APIを呼び出さない
propsにのみ依存することで、同じpropsに対して常に同じものが表示されるようにでき、デザインのデバッグが楽になる
Presentational Componentの例
import "./styles.css";
type ButtonProps = {
label: string;
text: string;
disabled: boolean;
onClick: React.MouseEventHandler<HTMLButtonElement>;
};
export const Button = (props: ButtonProps) => {
const { label, text, disabled, onClick } = props;
return (
<div className="button-container">
<span>{label}</span>
<button disabled={disabled} onClick={onClick}>
{text}
</button>
</div>
);
};
Container Componentの責務
- デザインは実装せず、ロジックのみを書く
- Hooksを持たせ、APIを実行する
- コンポーネントの振る舞い(ボタンをいつ無効化するか、ボタンを押した時の挙動はどうするか、など)
import { useState, useCallback } from "react";
import { Button } from "./ButtonPresentation";
type CountButtonProps = {
label: string;
max: number;
};
export const CountButton = (props: CountButtonProps) => {
const { label, max } = props;
const [count, setCount] = useState(0);
const onClick = useCallback(() => {
const newCount = count + 1;
setCount(newCount);
}, [count, max]);
const disabled = count >= max;
const text = disabled ? `もう押せません` : `${count}回クリックしました`;
return (
<div>
<Button label={label} text={text} disabled={disabled} onClick={onClick} />
</div>
);
};
Presentation と Container のイメージ
-
イメージ
ItemPageContainer |--- props ---> ButtonPresentation |--- props ---> SearchPresentation |--- props ---> ItemPresentation
-
Containerが親としてロジックを組む
-
Presentationが子としてpropsを使って画面を作る
Atomic Design
5つの階層に分けてデザインを定義
階層 | 説明 | 例 |
---|---|---|
Atoms | 最小の要素 | ボタン、テキスト |
Molecules | 複数のAtomsを組み合わせ | 検索フォームなど。1つの役割を持ったUIのみを実装する |
Organisms | Moleculesよりも具体的な要素 | ヘッダー、フッター、サイドバー、ボディーなど。ロジックはContainer Component、見た目はPresentational Componentに分けて実装する |
Templates | ページ全体のレイアウト | ワイヤフレームのようなイメージ。Organismを組み合わせてCSSでレイアウトしていく |
Pages | ページそのもの | コンテンツ、データを含めたページ要素全て。状態管理、ルーティング、API処理などを実装する |
以下のサイトで、違いが分かりやすく纏まっている