Reactにおける
「ステートフル(stateful)」コンポーネントと
「ステートレス(stateless)」コンポーネントの違いは、
その内部に状態(state)を持つかどうかです。
以下にその違いを詳しく説明します。
🧠 ステートフルコンポーネント(Stateful Component)
定義:
内部に useState や useReducer などを用いて状態(state)を持っているコンポーネント。
特徴:
- 状態の管理が可能
- 状態が変わると再レンダリングされる
- 複雑なUIロジックを持つことが多い
例:
jsximport React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // state を持っている
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>増やす</button>
</div>
);
}
🌿 ステートレスコンポーネント(Stateless Component)
定義:
状態を持たず、props(親コンポーネントから渡された値)だけ
を使って描画するコンポーネント。
特徴:
- 状態を持たないため純粋関数的
- テストがしやすい
- 再利用性が高い
- 表示専用、ロジックが少ない
例:
jsxfunction Greeting({ name }) {
return <p>こんにちは、{name}さん!</p>;
}
💡 使い分けの考え方
| シチュエーション | ステートフル | ステートレス |
|---|---|---|
| 状態を管理したい | ✅ | ❌ |
| 表示のみの処理 | ❌ | ✅ |
| 再利用性 | △(設計次第) | ✅ |
| 単純なUI | ❌ | ✅ |
補足:関数コンポーネント vs クラスコンポーネント
以前は、クラスコンポーネントだけがステートを持てる時代がありましたが、
React Hooks(useState, useEffect など)の登場により、
関数コンポーネントでもステートフルにできるようになりました。
プログラムのデザインパターン ロジックとUIの分離
「アプリケーションロジックはステートフルで管理し、UI(レンダリング)はステートレスで表現する」
という設計は、
効率的でメンテナンス性・再利用性にも優れたベストプラクティスの一つとされています。
✅ なぜこの分離が有効か?
1. 関心の分離(Separation of Concerns)
アプリケーションの
「ロジック(データの取得、状態管理、イベントハンドリングなど)」と、
「表示ロジック(UIの描画)」を別のコンポーネントに分けることで、
それぞれの責任が明確になります。
2. 再利用性の向上
- ステートレスな表示用コンポーネントは、
他のコンテキストでも再利用がしやすいです。
3. テストがしやすい
- ロジックとUIを分けることで、ロジックはユニットテスト、
UIはスナップショットテストなどで独立にテスト可能です。
4. 保守性と拡張性が高い
- アプリケーションの成長に伴い、状態やロジックが複雑化しても、
表示側の影響を最小限に抑えられます。
🧱 具体的な構造イメージ
jsx// ✅ ステートフル:ロジックを管理するコンテナ
function CounterContainer() {
const [count, setCount] = useState(0);
const increment = () => setCount((prev) => prev + 1);
return (
<CounterDisplay count={count} onIncrement={increment} />
);
}
// ✅ ステートレス:UIに特化した表示コンポーネント
function CounterDisplay({ count, onIncrement }) {
return (
<div>
<p>カウント: {count}</p>
<button onClick={onIncrement}>増やす</button>
</div>
);
}
🧠 補足:この設計を促進するパターン
- コンテナ & プレゼンテーショナルパターン(Container / Presentational Pattern)
- かつて Redux 時代によく使われていたパターンですが、今も理にかなっています。
- カスタムフックでロジックを分離
- ロジックを別ファイルや関数(
useCounterなど)にまとめることで、
より柔軟な分離が可能です。
- ロジックを別ファイルや関数(
jsxfunction useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = () => setCount((c) => c + 1);
return { count, increment };
}
🧩 注意点(万能ではない)
- 小規模アプリケーションでは、あまり分けすぎると逆に複雑になることも。
- 状態の量や頻度によっては、ステートレスで十分な場合もあるので、
「状況に応じて使い分ける」柔軟さが重要です。
✅ まとめ
| ポイント | 内容 |
|---|---|
| ロジック(状態管理) | ステートフルにしてアプリケーションの脳として機能させる |
| 表示(UI) | ステートレスにして純粋な表示関数として保つ |
| メリット | 再利用性・保守性・テスト容易性が向上 |
| 注意点 | 小規模アプリではやりすぎ注意。必要に応じて使い分ける。 |


