| name | component-design |
| description | デザインカンプ、スクリーンショット、HTML、既存画面、仕様メモなどの Input から React / Next.js / TypeScript の UI を実装する前に、画面構成、構成要素ツリー、コンポーネント境界、props、hooks、状態管理、実装順序を設計するために使う。新規画面作成、既存画面への UI 追加、大きな JSX の分割、UI リファクタリング、既存コンポーネントを探して再利用する実装、未実装の構成要素を順に消化する実装では必ず使う。単純な文言変更、色や余白だけの小変更、既に境界が明確な小さな修正だけなら使わない。 |
Component Design
目的
React の実装を、画面として動くだけでなく、変更しやすく、読みやすく、テストしやすいコンポーネント構造に落とし込む。
このスキルは、UI を細かく分けること自体ではなく、責務の境界を明確にすることを目的にする。コンポーネント、hooks、型、データ変換、イベント処理、表示部品のどこに責務を置くと次の変更が局所化するかを判断する。
入力がデザインカンプ、スクリーンショット、HTML、既存画面、仕様メモのどれであっても、まず画面全体の構造を捉え、構成要素のツリーとコンポーネント境界を決めてから実装する。
いつ使うか
このスキルは、React UI の実装前に「何をどのコンポーネントとして作るか」を決める必要があるときに使う。特に、Input を見て構成要素を洗い出し、既存コンポーネントを探し、足りない部品を新規作成しながら画面を完成させる作業で使う。
使う場面:
- デザインカンプ、スクリーンショット、HTML、既存画面、仕様メモから新しい UI を実装する
- 既存画面にセクション、フォーム、一覧、カード、モーダル、操作パネルなどを追加する
- 1 ファイルに大きく書かれた JSX を、構成要素ツリーとコンポーネント境界から分割する
- 既存コンポーネントを検索して再利用できるか判断する
- 新規コンポーネントの props、children、状態、イベントを先に設計したい
- 別エージェントへ UI 部品の実装を依頼するため、境界、契約、配置先を明確にしたい
- 未実装の構成要素が複数あり、実装順序と完了条件を管理しながら進めたい
使わない場面:
- 文言、リンク先、色、余白、アイコン差し替えだけの小変更
- 既存コンポーネントの props を 1 箇所変えるだけで完了する修正
- UI ではない API、DB、バッチ、ドメインロジックだけの実装
- 欠陥検出を目的としたコードレビュー。これは
code-review を優先する。
- テストケース設計だけを行う作業。これは
code-test を優先する。
併用
- 実装作業では
code-general も併用する。
- React 実装へ進む場合は、実装時の責務分離、Atomic Design の補助観点、hooks / props / state の判断基準として
code-react も併用する。
- テスト設計やテスト追加では
code-test も併用する。
- 実装済み差分の欠陥レビューでは
code-review を優先する。
- 次の開発者の読みやすさをレビューする場合は
code-next-developer-review も併用する。
code-react との使い分け
この skill は、実装前に画面構成、component tree、props、状態、hooks、実装順序を設計するために使う。
React 実装中の component 境界、Atomic Design の補助観点、hooks / props / state の責務分離を確認する場合は code-react を使う。
最初に確認すること
React のコードを書く前に、既存実装から次を確認する。
- ディレクトリ構成、命名、コンポーネント粒度、hooks の置き場所
- UI ライブラリ、フォームライブラリ、データ取得ライブラリ、状態管理の既存パターン
- props の型定義方針、ドメイン型と view model の境界
- Storybook、React Testing Library、E2E、lint、formatter の有無
- Server Component / Client Component、SSR、routing、data fetching の前提
- 既存のアクセシビリティ、国際化、デザインシステムの扱い
不明な場合は、近い画面や同じ責務のコンポーネントを優先して読む。新しい構成を持ち込む前に、既存の置き場所と命名に合わせる。
入力から構成を決める
最初に Input を読み、画面を実装単位へ分解する。Input には、デザインカンプ、スクリーンショット、HTML、既存画面、Figma 由来の画像、仕様メモ、ワイヤーフレームを含める。
- 画面全体の目的、主要なユーザー操作、情報の優先順位を把握する。
- レイアウトの大枠を、ページ、領域、セクション、繰り返し要素、操作部品に分ける。
- 各構成要素について、表示責務、入力 props、状態、イベント、依存データを仮置きする。
- 親子関係をツリーとして整理し、どこを既存コンポーネントで表現できそうか見当を付ける。
- 未確定の仕様、見た目、状態、エラー、空状態、権限条件を明示する。
Input が画像だけの場合でも、いきなり JSX を書かない。まず観察した構成要素を言語化し、画面ツリーと責務境界を作ってからコードへ移る。
実装ループ
構成要素を 1 つずつ実装し、全ての要素が画面に配置されるまでループする。
- Input から全体構成を検討する。
- デザインカンプ、スクリーンショット、HTML、既存画面、仕様メモを読み、画面の目的と情報構造を把握する。
- レイアウトの大枠、主要セクション、繰り返し要素、ユーザー操作、状態を整理する。
- 画面の構成要素を洗い出し、ツリー構造とコンポーネント境界を検討する。
- ページ、レイアウト、セクション、リスト、カード、フォーム、ボタン、モーダルなどに分ける。
- 各ノードについて、props、children、状態、イベント、データ変換の責務を仮決めする。
- 既存コンポーネントを使う候補と、新規作成が必要そうな候補を分ける。
- 実装ループを回す。
- 未実装の構成要素から 1 つ選ぶ。
- コンポーネント境界と一致しそうな既存コンポーネントをコード上から検索する。
- 見つかった場合は、そのコンポーネントをベースに構成要素を配置する。
- 見つからない場合は、新しいコンポーネントを作成する。
- 新規作成時は、先に props などのインターフェースを定義する。
- 新規作成時に作業を分担できる場合は、定義したインターフェース、期待する表示、状態、イベント、配置先を明示して別エージェントへ実装を依頼する。
- 実装後、未実装の構成要素が残っていれば、次の構成要素について同じ手順を繰り返す。
- 全ての構成要素が実装されるまで、3 のループを続ける。
- 最終的なコードをレビューし、品質を確保する。
- コンポーネント境界、props 契約、状態の置き場所、アクセシビリティ、既存 UI との一貫性、テスト容易性を確認する。
- 未実装の構成要素、未対応状態、重複実装、props の過不足が残っていないか確認する。
別エージェントへ依頼する場合は、丸投げにしない。依頼単位はコンポーネント境界に合わせ、書き込み範囲、props 契約、期待する DOM/表示状態、既存パターン、検証方法を渡す。
責務分離の判断
Component
コンポーネントは、表示構造とユーザー操作の受け口を担当する。
- props から表示できる単位にする
- props 名は UI 都合ではなく、利用側が渡したい概念に寄せる
- コンポーネント内部にドメイン判断、API 呼び出し、複雑な変換を抱え込まない
- 条件分岐が増える場合は、表示パターンごとの小さなコンポーネントへ分ける
children はレイアウトや枠組みの再利用に効く場合だけ使う
Hook
custom hook は、状態、派生値、イベント手続き、副作用をまとめる場所として使う。
- 画面固有の状態遷移やイベント処理は hook に出す
- API、router、storage、timer などの副作用は hook か既存の service 層に寄せる
- hook の戻り値はコンポーネントがそのまま描画に使える形にする
- hook 名は
useFeatureName や useXxxForm のように利用目的で付ける
- 汎用化は 2 つ目の実利用が見えてからにする
View Model
API レスポンスやドメイン型をそのまま深い UI に流し込むと、表示都合と契約が混ざりやすい。必要に応じて view model を作る。
- UI が必要とする値、ラベル、状態だけを持つ型に変換する
- 表示用の整形、ソート、グルーピング、空状態の判定は小さな関数に切り出す
- 変換関数は React から独立させ、単体テストしやすくする
- API 型、ドメイン型、フォーム値、表示値を同じ型で兼用しない
Event Handler
イベントハンドラは、ユーザー操作の意味が読める名前にする。
onClick の中に長い処理を書かず、handleSubmit, handleSelectItem のように意図を分ける
- 子コンポーネントへ渡す callback は
onSave, onCancel, onChangeFilter のように外部契約として命名する
- 複数の副作用を持つ操作は、手続きの順序とエラー扱いが分かる単位に分ける
コンポーネント分割の基準
分割は行数ではなく、変更理由で判断する。
分けるべきサイン:
- 表示、データ取得、入力検証、権限制御、整形処理が 1 つのファイルに混在している
- 同じ JSX のまとまりが複数回出てくる
- 1 つの state 更新が画面の複数箇所に影響し、追跡しづらい
- 条件分岐が UI パターンごとに増えている
- テストしたいロジックが DOM 操作前提になっている
分けすぎのサイン:
- props が親から子、孫へそのまま通過するだけの層が増えている
- コンポーネント名が
Wrapper, Container, Content ばかりになる
- 1 回しか使わない 3 行程度の JSX を名前の弱い部品にしている
- 変更時にファイルジャンプが増えるだけで責務が明確になっていない
Props 設計
props はコンポーネントの公開契約なので、利用側の誤用を減らす型にする。
- 必須値と任意値を曖昧にしない
- boolean props が増える場合は union 型や variant にする
data, item, value のような曖昧な名前を避け、領域の意味を入れる
- callback props は発火条件と渡す値が型から分かるようにする
- 外部へ公開する component props は UI ライブラリの型を漏らしすぎない
例:
type SaveButtonProps =
| { state: "idle"; onSave: () => void }
| { state: "saving"; onSave?: never }
| { state: "disabled"; reason: string; onSave?: never };
状態管理
状態は、必要な最小範囲に置く。
- 1 コンポーネント内で完結する UI 状態は local state にする
- URL と同期すべき検索条件やタブは router の既存パターンに合わせる
- サーバー由来の状態は query cache や framework の data fetching に寄せる
- 複数画面で共有する状態だけ、既存の global store や context を使う
- 派生値を state として重複保持しない。
useMemo や純粋関数で表現する
Context は広域の再レンダリングや暗黙依存を作りやすい。テーマ、認証、設定など本当に広域の前提に向く。単なる props 受け渡し回避だけなら、コンポーネント境界や hook の設計を見直す。
フォーム
フォームは、入力値、検証、送信、表示を分ける。
- 既存のフォームライブラリと schema validation の流儀に合わせる
- form value と API request 型を分け、送信前に明示的に変換する
- validation error、server error、通信中、送信成功の状態を区別する
- 入力部品は controlled / uncontrolled の方針を混在させない
- ラベル、エラー表示、disabled、aria 属性を部品化して抜け漏れを減らす
一覧・詳細・ダッシュボード
データ量や状態の組み合わせが増えやすい画面では、描画前に表示モデルを作る。
- loading、empty、error、success を明示的に分ける
- filter、sort、pagination、selection はそれぞれ責務を分ける
- table row や card の中で重い変換や権限判断を繰り返さない
- 集計値や badge label は純粋関数で作り、テスト可能にする
- 仮想化や memo 化は、実際に必要な描画コストがある場合に導入する
アクセシビリティ
コンポーネント志向は、見た目だけでなく操作契約も部品に閉じ込める。
- button と link を役割で使い分ける
- icon button には accessible name を付ける
- input と label、error message の関連を保つ
- modal、menu、tabs、combobox は既存 UI ライブラリの accessible な部品を優先する
- キーボード操作と focus 管理を壊さない
テスト方針
テストは責務境界に合わせて選ぶ。
- 表示分岐とユーザー操作は React Testing Library で確認する
- データ変換、整形、状態遷移は純粋関数や hook 単位で確認する
- API 連携は既存の mock 方針に合わせる
- 実装詳細の state 名や private なコンポーネント構造に依存しすぎない
- ユーザーが見る文言、role、label、状態変化を優先して検証する
実装時の注意
実装は必ず「入力から構成を決める」から始め、「実装ループ」で構成要素を 1 つずつ消化する。近い既存画面を読み、コンポーネント粒度、hooks、型、テストの置き方を把握したうえで、既存コンポーネントを優先して使う。
新規コンポーネントを作る場合は、JSX を先に書き始めず、公開 props、主要な型、状態、イベント、依存データを先に決める。複雑な変換や分岐は React から独立した関数または hook に出し、JSX は状態ごとの見通しがよい形に整える。
各ループの終わりで、実装済みの構成要素と未実装の構成要素を確認する。全要素を配置した後に、既存の lint、format、test を実行し、差分を見直す。
完了前チェック
- 画面固有ロジックと汎用 UI 部品の責務が混ざっていない
- props の型から利用方法と禁止状態が分かる
- API 型、フォーム型、表示型の境界が必要に応じて分かれている
- loading、empty、error、disabled、permission などの状態が抜けていない
- アクセシビリティ上の名前、role、label、focus を壊していない
- 主要な表示分岐や状態遷移を検証できる
- 既存コードの命名、配置、UI ライブラリに揃っている
出力
最終報告では、次を簡潔に伝える。
- コンポーネント境界として何をどこへ分けたか
- props、hook、view model、状態管理で決めた契約
- 実行した検証
- 残る未検証事項や、今後分割するとよい候補