Reactコンポーネントの基本:関数型とクラス型コンポーネントの徹底解説

2025-08-07

Reactの核心概念である「コンポーネント」について、初心者向けに詳細に解説します。コンポーネントはUIを独立した再利用可能な部品に分割するための仕組みで、Reactアプリケーションを構築する基礎ブロックとなります。

コンポーネントとは何か?

コンポーネントの基本概念

コンポーネントはReactアプリケーションを構成する独立したUI部品です。以下の特徴を持ちます:

  • 自己完結的:特定の機能や見た目をカプセル化
  • 再利用可能:同じコンポーネントを複数箇所で使用可能
  • 組み合わせ可能:小さなコンポーネントを組み合わせて複雑なUIを構築
// シンプルなボタンコンポーネントの例
function Button() {
  return <button>クリックしてください</button>;
}

コンポーネントの利点

  1. コードの再利用性向上:同じコンポーネントを複数箇所で使用
  2. メンテナンス性向上:機能ごとにコードを分割
  3. 開発効率向上:チームメンバーが別々のコンポーネントを並行開発
  4. テスト容易性:コンポーネント単位でテスト可能

関数型コンポーネント

関数型コンポーネントの基本

関数型コンポーネントはJavaScriptの関数として定義され、propsを引数として受け取り、React要素を返します。

function Greeting() {
  return <h1>こんにちは、Reactの世界へ!</h1>;
}

アロー関数での記述

ES6のアロー関数を使用してより簡潔に記述できます。

const Greeting = () => {
  return <h1>こんにちは、Reactの世界へ!</h1>;
};

// 暗黙のreturnを使用すればさらに簡潔に
const Greeting = () => <h1>こんにちは、Reactの世界へ!</h1>;

関数型コンポーネントの特徴

  1. シンプルな構文:クラスよりも簡潔に記述可能
  2. パフォーマンス:クラスコンポーネントより軽量
  3. Hooks対応:React 16.8以降、状態管理も可能に
  4. 推奨方法:現在のReactでは関数型コンポーネントが主流

実用的な関数型コンポーネントの例

const UserProfile = () => {
  const user = {
    name: '山田太郎',
    age: 28,
    hobbies: ['読書', '旅行', '写真']
  };

  return (
    <div className="profile">
      <h2>{user.name}</h2>
      <p>年齢: {user.age}歳</p>
      <h3>趣味:</h3>
      <ul>
        {user.hobbies.map((hobby, index) => (
          <li key={index}>{hobby}</li>
        ))}
      </ul>
    </div>
  );
};

クラス型コンポーネント

クラス型コンポーネントの基本

クラス型コンポーネントはES6クラスとして定義され、React.Componentを継承します。

import React from 'react';

class Greeting extends React.Component {
  render() {
    return <h1>こんにちは、Reactの世界へ!</h1>;
  }
}

クラス型コンポーネントの構造

クラスコンポーネントにはいくつかの必須要素があります:

  1. React.Componentの継承
  2. render()メソッド:必須、React要素を返す
  3. コンストラクタ(任意):stateの初期化など
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return (
      <div>
        <p>現在のカウント: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          増やす
        </button>
      </div>
    );
  }
}

クラス型コンポーネントの特徴

  1. ライフサイクルメソッド:コンポーネントの各段階で処理を実行可能
  2. state管理:コンポーネント固有の状態を保持
  3. thisの使用:メソッド内でthisを使用してプロパティやメソッドにアクセス
  4. 歴史的経緯:以前は状態管理にはクラスが必要だった

関数型とクラス型の比較

構文の違い

特徴関数型コンポーネントクラス型コンポーネント
定義方法関数class、extends React.Component
状態管理useState Hookthis.state
ライフサイクルuseEffect Hookライフサイクルメソッド
thisの使用不要必要
コード量少ない多い

使用推奨

現在のReact(バージョン16.8以降)では、関数型コンポーネントとHooksの使用が推奨されています。新規プロジェクトでは関数型コンポーネントを使用するのが良いでしょう。

ただし、既存のコードベースでクラスコンポーネントが使用されている場合や、特定のライブラリがクラスコンポーネントを要求する場合など、クラスコンポーネントの知識も必要です。

コンポーネントの命名規則

コンポーネント名にはパスカルケース(大文字で始まる)を使用します。

// 正しい例
function UserProfile() { /* ... */ }
class ShoppingCart extends React.Component { /* ... */ }

// 誤った例
function userProfile() { /* ... */ }
class shopping_cart extends React.Component { /* ... */ }

この命名規則は重要で、Reactは大文字で始まるコンポーネントをカスタムコンポーネントとして認識します。

コンポーネントの分割のベストプラクティス

いつコンポーネントを分割すべきか?

  1. UIが複雑になったとき
  2. 同じUIパターンが繰り返されるとき
  3. コンポーネントが複数の責務を持っているとき
  4. 再利用が必要な部分があるとき

分割の例:ユーザーカードコンポーネント

// 分割前のモノリシックなコンポーネント
const UserProfile = () => {
  // ...多くのコード...
};

// 分割後のコンポーネント
const UserAvatar = () => { /* ... */ };
const UserInfo = () => { /* ... */ };
const UserHobbies = () => { /* ... */ };

const UserProfile = () => (
  <div className="user-profile">
    <UserAvatar />
    <UserInfo />
    <UserHobbies />
  </div>
);

コンポーネントの実践例

関数型コンポーネントの実例:Todoアイテム

const TodoItem = ({ task, completed }) => {
  return (
    <li className={`todo-item ${completed ? 'completed' : ''}`}>
      <input type="checkbox" checked={completed} readOnly />
      <span>{task}</span>
    </li>
  );
};

// 使用例
<TodoItem task="Reactを学ぶ" completed={false} />

クラス型コンポーネントの実例:タイマー

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { seconds: 0 };
  }

  componentDidMount() {
    this.interval = setInterval(() => {
      this.setState(prevState => ({
        seconds: prevState.seconds + 1
      }));
    }, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>
        <p>経過時間: {this.state.seconds}秒</p>
      </div>
    );
  }
}

コンポーネントのファイル構成

プロジェクトが成長するにつれ、コンポーネントを適切に整理することが重要です。

推奨されるファイル構造

src/
  components/
    Button/
      Button.jsx
      Button.css
      index.js
    Header/
      Header.jsx
      Header.css
      index.js
    ...

index.jsの役割

// src/components/Button/index.js
export { default } from './Button';

これにより、インポート時にディレクトリ名だけでコンポーネントを参照できます。

import Button from './components/Button';

コンポーネント開発のデバッグ技法

よくあるエラーと解決策

  1. コンポーネントが表示されない
  • コンポーネント名が大文字で始まっているか確認
  • エクスポート/インポートが正しいか確認
  1. TypeError: Cannot read property…
  • thisのバインドを確認(クラスコンポーネント)
  • propsの存在を確認
  1. Unexpected tokenエラー
  • JSX構文の誤りを確認(タグの閉じ忘れなど)

デバッグツール

  1. React Developer Tools
  • コンポーネント階層を検査
  • propsとstateを表示
  1. コンソールログ
const MyComponent = (props) => {
  console.log('Props:', props);
  return <div>...</div>;
};
  1. デバッガーステートメント
   debugger; // 実行を一時停止

コンポーネント設計のベストプラクティス

  1. 単一責任の原則
    1つのコンポーネントは1つの役割だけを持つ
  2. 適切な分割
    大きすぎるコンポーネントは分割を検討
  3. 再利用性
    汎用的なコンポーネントは再利用可能に設計
  4. 命名の明確化
    コンポーネント名から役割がわかるように
  5. プレゼンテーション/コンテナコンポーネントの分離
  • プレゼンテーション:見た目だけを担当
  • コンテナ:データ処理や状態管理を担当

次に学ぶべきこと

コンポーネントの基本を理解したら、次のステップとして以下の概念を学びましょう:

  1. PropsとStateの管理
  • 親から子コンポーネントへのデータ渡し(Props)
  • コンポーネント内部の状態管理(State)
  1. イベント処理
  • ユーザー操作への対応(onClickなど)
  1. ライフサイクル
  • コンポーネントのマウント/更新/アンマウント時の処理
  1. フォーム処理
  • 制御されたコンポーネント(Controlled Components)の実装

コンポーネントはReactの核心概念です。関数型とクラス型の違いを理解し、適切な場面で使い分けられるようにしましょう。最初はシンプルなコンポーネントから始めて、徐々に複雑なものを作成していくのがおすすめです。