命名と責務が一致しないコンポーネントの再設計指針
はじめに
React 開発では 「名前は軽快でも中身は巨大」 ― そんなコンポーネントに出会うことが珍しくありません。
レビューアーは 命名と実装責務の乖離 を早期に検出しなければ、後続開発者の認知負荷を増大させます。本稿では、命名と責務がずれている兆候 を整理し、再設計の観点と提案方法をまとめます。
検索キーワード:React コンポーネント 責務分離, 命名 規約, ファットコンポーネント リファクタリング
なぜ命名と責務がずれるのか
- 初期スコープの肥大化
MVP フェーズで仮配置したロジックが段階的に膨張し、命名更新が置き去りになる。 - 業務ドメインの曖昧さ
ビジネス用語と UI 用語が混在し、適切な抽象度が見えなくなる。 - レビュー観点の不足
「ファイルサイズ」「行数」の定量的指標だけを注視し、名前と内部構造の意味的整合 を検査しない。 
用語解説:ファットコンポーネントとは
「単一責任の原則」を満たさず、多数の状態・副作用・イベント処理を抱えた巨大なコンポーネントの俗称です。可読性・再利用性・テスト容易性が損なわれる傾向にあります。
兆候チェックリスト
- ファイル名と export 名が UI 意図を示さない
例:Dashboard.jsxが内部でモーダルや REST 呼び出しまで担う。 useEffectが複数の無関連副作用を処理- Props が10項目を超え、プレーンオブジェクトでバケツリレー
 - ハンドラ名が 
handleClick*系で乱立し、ユースケースが読めない - 他レイヤー(API / Router / i18n)への直接依存が3種以上
 
レビュー観点 1:命名の粒度と責務の照合
ダッシュボードコンポーネント(初版)
export function Dashboard() {
  const [users, setUsers] = useState<User[]>([]);
  const [open, setOpen] = useState(false);
  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(setUsers);
@ReviewerREST 呼び出しは別 Hook へ抽出し、UI から切り離す方が読みやすいです  }, []);
  const handleSubmit = (payload: NewUser) => {
    fetch('/api/users', { method: 'POST', body: JSON.stringify(payload) })
      .then(() => setOpen(false));
@Reviewer「Dashboard」という名前から POST 処理は連想しづらいです。責務が混在しています  };
  return (/* 略 */);
}- 診断
- コンポーネント名から ユーザ追加ロジック を想像しづらい
 useEffectとhandleSubmitがネットワーク境界を直接操作- 命名を変えるべきか、責務を分割すべきか両面検討
 
 
レビュー観点 2:命名再考 or 責務分離の判断基準
- UI レイヤーが唯一の責務 → 名前を UI コンポーネント視点に統一
 - 副作用・データ取得・状態計算を同居 → 専用 Hook / Container で分離
 - 機能単位のまとまりが 300 行超 → ファイル物理分割 + 名前の再定義
 
再設計パターン
パターンA:Custom Hook へ副作用を移譲
副作用切り出し例
function useUsers() {
  const [users, setUsers] = useState<User[]>([]);
  const fetchUsers = async () => { /* 略 */ };
  useEffect(() => { fetchUsers(); }, []);
  return { users, fetchUsers };
}
export function UserDashboard() {
  const { users, fetchUsers } = useUsers();
  // UI 描画に専念
}- 効果 : 命名が 
UserDashboardで UI 意図に集中 - 残課題 : POST 処理が UI 内に残るかどうか
 
パターンB:Container / Presentational 分割
分割構成
src/
 ├ containers/
 │   └ UserDashboardContainer.tsx
 └ components/
     └ UserDashboard.tsx- コンテナは 
useUsersとuseCreateUserを合成 - 純粋 UI は props 経由で描画し、副作用を持たない
 
パターンC:ディレクトリごとの Bounded Context
業務ドメインが複合の場合、ディレクトリ単位で責務境界 を設ける。
src/
 └ user/
     ├ ui/
     │   └ Dashboard.tsx
     ├ hooks/
     │   ├ useUsers.ts
     │   └ useCreateUser.ts
     └ model/
         └ user.ts
UMLで可視化する依存関係
ケーススタディ:命名と責務の乖離をレビューでどう指摘するか
リアルなPR抜粋
export function Analytics() {
  const [activeTab, setActiveTab] = useState<'daily' | 'monthly'>('daily');
  // REST, chart.js, i18n… 500行超
@Reviewer- コンポーネント名に対して内部責務が多岐にわたります- データ取得・チャート描画・翻訳切替は別層へ分割しUI はタブ切替とプレゼンテーションだけに集中させましょう@Developer分割後の命名は `AnalyticsContainer` / `AnalyticsChart` で考えていますご意見ください}- レビューポイント
- 名前再考:
Analyticsが広義すぎる場合は限定語を付す - 責務抽出:
ChartRenderer,useAnalyticsData,TabState等へ分割 - テスト戦略:分割により単体テストが可能になりカバレッジ向上
 
 - 名前再考:
 
エビデンスと参考資料
- React公式ブログ「A Complete Guide to Component Design」(2024-11-12 公開)
 - GitHub Octoverse 2024 Report 「Top React Antipatterns」
 - Nielsen Norman Group UX Research 「Component Naming and Cognitive Load」(調査番号 NN-UX-22-C013)
 
まとめ
命名と責務の乖離は コード迷子 を招き、保守コストを跳ね上げます。
レビューアーは「名前→責務→依存」の三段階で照合し、分割と命名の両輪 で再設計を提案することが望ましいです。まずは Custom Hook 抽出や Container 分離といった 低コストなリファクタ から着手し、コンポーネントの意図を名前に正しく映し出す構造を目指しましょう。
