← ブログ一覧に戻る

Reactを基礎から学び直す #2: コンポーネント設計の基礎(関数コンポーネント・Props・State)

2026.07.29

フリーランスでWeb制作をしている矢野です。

前回は、Reactを基礎から学び直すことにした理由を書きました。

今回からは実際に基礎を整理していきます。

まずはシリーズの土台になる、コンポーネント・Props・Stateの3つです。

そもそも「コンポーネント」とは

Reactにおけるコンポーネントは、UIの一部を返す関数のことです。

以前はクラスで書くこともありましたが、今はほとんどの場面で関数コンポーネントを使います。

RE:FITでも、診断の各質問画面をそれぞれ1つのコンポーネントとして分けて実装しました。

たとえば「トレーニングの目的は?」という最初の質問は、GoalQuestionという1つのコンポーネントです。

Props:親から子へデータを渡す仕組み

Propsは、親のコンポーネントから子のコンポーネントに値を渡すための仕組みです。

GoalQuestionのコードを見てみます。

type Props = {
  value: Goal | null;
  onSelect: (goal: Goal) => void;
  onBack: () => void;
};

export default function GoalQuestion({ value, onSelect, onBack }: Props) {
  // ...
}

value(今選ばれている目的)、onSelect(選択されたときの処理)、onBack(戻るときの処理)の3つを、親のコンポーネントから受け取っています。

ポイントは、GoalQuestion自身はこれらの値を書き換えられないということです。

選択された、という事実をonSelect経由で親に伝えるだけで、実際に値を更新するのは親側の役目になります。

このときは何となく「そういうものだ」で書いていたのですが、あらためて整理すると、子コンポーネントは親から預かったデータを表示・通知するだけの窓口だと考えると腑に落ちました。

State:コンポーネントが自分で持つ値

一方でStateは、コンポーネント自身が管理する値です。

RE:FITの予約カレンダー画面BookingScreenでは、カレンダーのデータをコンポーネント内のStateとして持たせています。

const [calendar] = useState<CalendarDay[]>(() =>
  generateCalendar(new Date())
);

このカレンダーのデータは、診断結果や予約日時のように他のコンポーネントと共有する必要がありません。

BookingScreenが表示されるたびに生成すればいい、その場限りのデータです。

だからこそ、Propsで親から受け取るのではなく、コンポーネント自身のStateとして持たせています。

PropsとStateの境界線をどう引いたか

書きながら気づいたのは、「このデータは誰が持つべきか」を都度考える必要があるということです。

RE:FITでは、診断の回答や予約日時のように画面をまたいで使うデータは、個々のコンポーネントのStateではなく、後述する仕組みで一箇所にまとめて管理しています。

反対に、BookingScreenのカレンダーのように、その画面の中だけで完結するデータはコンポーネント自身のStateに閉じています。

「複数の画面で必要か、その場限りか」が、PropsとStateはもちろん、State自体をどこに置くかを判断する基準になっていました。

この「複数の画面をまたぐ状態をどう管理するか」は、シリーズ第4回であらためて詳しく書く予定です。

まとめ

今回は、コンポーネント・Props・Stateという3つの基礎を、RE:FITの実際のコードを見ながら整理しました。

Propsは親から子へのデータの受け渡し、Stateはコンポーネント自身が持つ値、という役割の違いがポイントです。

次回は、Stateを実際に扱うためのHooks、特にuseStateuseEffectの実践的な使い方を書きます。