0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactコンポーネントの合成パターンを理解する

Posted at

はじめに

Reactでアプリケーションを開発する際、最も重要な概念の一つが「コンポーネントの合成(Composition)」です。本記事では、小さなコンポーネントを組み合わせて、より複雑な機能を実現する方法について解説します。

コンポーネント合成とは

Reactは「継承」よりも「合成」を推奨しています。これは、小さくシンプルなコンポーネントを組み合わせることで、大きく複雑なアプリケーションを構築するアプローチです。

合成パターンの基本構造

概念 説明
合成(Composition) 小さなコンポーネントを組み合わせて大きなコンポーネントを作る
継承(Inheritance) Reactでは推奨されない。親クラスを拡張する手法
Props 親から子へデータを渡す仕組み
コールバック 子から親へ情報を伝える関数

実装例:多肢選択コンポーネント

ラジオボタンを使った多肢選択問題コンポーネントを例に、合成パターンを実装してみます。

コンポーネントの階層構造

MultipleChoiceQuestion(親)
    └── RadioInput(子)× 複数
            └── input要素

1. RadioInputコンポーネントの実装

interface RadioInputProps {
  id?: string;
  name: string;
  label: string;
  value: string;
  checked?: boolean;
  onChanged?: (value: string) => void;
}

const RadioInput: React.FC<RadioInputProps> = ({
  name,
  label,
  value,
  checked = false,
  onChanged
}) => {
  const handleChange = () => {
    onChanged?.(value);
  };

  return (
    <div className="radio">
      <label>
        <input
          type="radio"
          name={name}
          value={value}
          checked={checked}
          onChange={handleChange}
        />
        {label}
      </label>
    </div>
  );
};

2. MultipleChoiceQuestionコンポーネントの実装

interface Choice {
  value: string;
  label: string;
}

interface MultipleChoiceQuestionProps {
  label: string;
  choices: Choice[];
  value?: string;
  onCompleted: (value: string) => void;
}

const MultipleChoiceQuestion: React.FC<MultipleChoiceQuestionProps> = ({
  label,
  choices,
  value,
  onCompleted
}) => {
  const [selectedValue, setSelectedValue] = useState(value);

  const handleChanged = (newValue: string) => {
    setSelectedValue(newValue);
    onCompleted(newValue);
  };

  return (
    <div className="form-group">
      <label className="survey-item-label">{label}</label>
      <div className="survey-item-content">
        {choices.map((choice) => (
          <RadioInput
            key={choice.value}
            name="question"
            label={choice.label}
            value={choice.value}
            checked={selectedValue === choice.value}
            onChanged={handleChanged}
          />
        ))}
      </div>
    </div>
  );
};

親子間の通信パターン

データフローの仕組み

方向 手段 用途
親→子 Props データや設定値の受け渡し
子→親 コールバック関数 イベントや状態変更の通知

通信の実装ポイント

  1. 親コンポーネント:コールバック関数を定義してpropsとして渡す
  2. 子コンポーネント:イベント発生時にコールバック関数を呼び出す
  3. 状態管理:親コンポーネントで一元管理することが推奨

使用例

const App: React.FC = () => {
  const choices = [
    { value: "1", label: "選択肢A" },
    { value: "2", label: "選択肢B" },
    { value: "3", label: "選択肢C" }
  ];

  const handleComplete = (value: string) => {
    console.log("選択された値:", value);
  };

  return (
    <MultipleChoiceQuestion
      label="質問内容"
      choices={choices}
      onCompleted={handleComplete}
    />
  );
};

まとめ

コンポーネントの合成パターンを使用することで、以下のメリットが得られます。

  • 再利用性の向上:小さなコンポーネントは様々な場面で再利用可能
  • 保守性の向上:各コンポーネントの責務が明確になる
  • テストの容易さ:独立したコンポーネントは個別にテスト可能
  • 柔軟な拡張:新機能の追加が容易

Reactの合成パターンは、HTMLの要素を拡張する自然な方法です。基本的な要素から始めて、段階的に機能を追加していくことで、複雑なUIコンポーネントを構築できます。このアプローチにより、コードの見通しが良くなり、メンテナンスしやすいアプリケーションを開発することができます。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?