目次
- Reactのコンポーネントとは?
- クラスコンポーネントの仕組みと特徴
- 関数コンポーネントの仕組みと特徴
- クラスコンポーネントと関数コンポーネントの比較
- Reactフック(Hooks)とは?
- 主要フックの詳細解説
- カスタムフックの活用
- よくあるエラーと注意点
- まとめ・次のステップ
1. Reactのコンポーネントとは?
Reactのコンポーネントは、UIを構成する再利用可能な部品です。
「ボタン」「リスト」「ページ」など、画面の一部をひとつのコンポーネントとしてまとめます。
2. クラスコンポーネントの仕組みと特徴
クラスコンポーネントは、React初期から使われている伝統的なコンポーネント定義方法です。
JavaScriptのclass
構文を使い、React.Component
を継承して作成します。
主な特徴:
-
render()
メソッドでUI(JSX)を返す -
this.state
で内部状態を管理 -
setState()
で状態を更新 -
componentDidMount
やcomponentDidUpdate
など、ライフサイクルメソッドを使える - propsは
this.props
で参照
例:
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
</div>
);
}
}
export default MyComponent;
メリット:
- 複雑な状態やライフサイクル制御がしやすい
- オブジェクト指向に馴染みがある人には理解しやすい
デメリット:
- 構文が複雑で冗長になりやすい
-
this
の扱いが難しい - コード量が多くなりがち
- フック(Hooks)は使えない
3. 関数コンポーネントの仕組みと特徴
関数コンポーネントは、よりシンプルな構文でコンポーネントを定義できる方法です。
JavaScriptの関数として定義し、propsを引数で受け取り、JSXを返します。
主な特徴:
- シンプルな関数として記述
- propsは引数で受け取る
- Hooks(フック)を使うことで、状態管理や副作用処理が可能
例:
import React from 'react';
const MyComponent = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<p>Count: {count}</p>
</div>
);
};
export default MyComponent;
メリット:
- 構文がシンプルで短い
- フックを使えばクラスコンポーネントと同じ機能が実現可能
- 再利用やテストがしやすい
-
this
の扱いで悩まない
デメリット:
- Hooks導入前は、状態やライフサイクル制御ができなかった
4. クラスコンポーネントと関数コンポーネントの比較
項目 | クラスコンポーネント | 関数コンポーネント |
---|---|---|
定義方法 | class構文+React.Component継承 | 関数(function/アロー関数) |
状態管理 | this.state / setState | useState, useReducer(Hooks) |
ライフサイクル制御 | componentDidMount等の専用メソッド | useEffect, useLayoutEffect(Hooks) |
コードの簡潔さ | 冗長になりやすい | シンプルで短い |
Hooksの利用 | 不可 | 可能 |
テスト・再利用性 | やや低い | 高い |
初心者の学習コスト | 高め(thisやライフサイクルの理解が必要) | 低め |
現在は関数コンポーネント+フックが主流です。
5. Reactフック(Hooks)とは?
**Reactフック(Hooks)**は、関数コンポーネントで「状態管理」や「副作用処理」などを実現するための特別な関数群です。
これにより、クラスコンポーネントでしかできなかった高度な機能も、シンプルな関数コンポーネントで実装できるようになりました。
6. 主要フックの詳細解説
useState ― 状態管理の基本
- 用途:コンポーネント内で値(状態)を保持・更新したいとき
- 特徴:初期値を渡して呼び出し、[現在値, 更新関数]の配列を返す
const [count, setCount] = useState(0);
setCount(count + 1); // 状態を更新
- 状態は直接変更せず、必ず更新関数を使う
useReducer ― 複雑な状態管理
- 用途:複数の値をまとめて管理したい、状態遷移が複雑な場合
- 特徴:reducer関数とdispatchで状態を操作
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, initialState);
- Reduxのような書き方ができる
useEffect ― 副作用の処理
- 用途:データ取得、イベント登録、タイマー設定などの副作用処理
- 特徴:依存配列で実行タイミングを制御、クリーンアップも可能
useEffect(() => {
// 副作用処理
return () => {
// クリーンアップ
};
}, [依存値]);
- 空配列ならマウント時のみ実行
useLayoutEffect ― レイアウト後の副作用
- 用途:DOMのレイアウトが確定した直後に実行したい場合
- 特徴:useEffectよりも早いタイミングで実行される
useLayoutEffect(() => {
// レイアウト直後の処理
}, []);
- レイアウト計測やスクロール位置調整に便利
useRef ― 値やDOM参照の保持
- 用途:再レンダリング不要な値やDOM要素の参照を保持
- 特徴:ref.currentで値を保持、変更しても再描画されない
const inputRef = useRef(null);
<input ref={inputRef} />
- 前回値やタイマーIDの保持にも使える
useImperativeHandle ― ref経由でメソッド公開
- 用途:親コンポーネントから子コンポーネントのメソッドを呼び出したいとき
- 特徴:forwardRefと組み合わせて使う
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus()
}));
return <input ref={inputRef} />;
});
- 内部実装を隠しつつ必要なメソッドだけ公開できる
useMemo ― 計算結果のメモ化
- 用途:計算コストの高い処理の結果をメモ化
- 特徴:依存値が変わらない限り再計算しない
const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- パフォーマンス最適化に有効
useCallback ― 関数のメモ化
- 用途:関数をメモ化して不要な再レンダリングを避ける
- 特徴:依存値が変わらなければ同じ関数参照を維持
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
- 子コンポーネントへのコールバック最適化に使う
useContext ― グローバル値の共有
- 用途:テーマや認証情報などグローバルな値を共有
- 特徴:Contextオブジェクトを作成し、useContextで値を取得
const ThemeContext = React.createContext("light");
const theme = useContext(ThemeContext);
- Providerで値を供給し、ツリー内のどこからでも参照可能
useDebugValue ― デバッグ用ラベル
- 用途:カスタムフックの値をReact DevToolsで見やすくする
- 特徴:開発時のデバッグ支援
useDebugValue(value ? "有効" : "無効");
7. カスタムフックの活用
複数のコンポーネントで使いたいロジックを「カスタムフック」としてまとめて再利用できます。
カスタムフックはuse
で始まる関数名にし、内部で他のフックを自由に組み合わせてOKです。
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
8. よくあるエラーと注意点
-
Invalid hook call
→ フックは関数コンポーネントまたはカスタムフックのトップレベルでのみ使う -
useEffectの依存配列ミス
→ 無限ループや意図しない挙動の原因 - useRefの値を直接変更しても再描画されない
- useContextの値が変わると、ツリー内のすべての利用箇所が再レンダリングされる
9. まとめ・次のステップ
- Reactのコンポーネントは「クラス」と「関数」の2種類
- 現在は関数コンポーネント+フックが主流
- フックを使えば、状態管理・副作用・パフォーマンス最適化・グローバル値共有など、あらゆる機能がシンプルに実装可能
- まずは
useState
とuseEffect
から慣れよう - カスタムフックでロジックを再利用しよう
フックを理解すれば、React開発が一気に楽しく・効率的になります!
ぜひこの記事を参考に、全フックとコンポーネントの違いをしっかり身につけてください。
※本記事は2025年6月時点のReact最新情報と公式ドキュメント、各種解説記事を参考に執筆しています。