React Hooksとは何か|誕生の背景と重要性
React Hooksは2019年にReact 16.8で導入された機能で、関数コンポーネントでstateとライフサイクル機能を使えるようにした革新的な仕組みです。それ以前はclassコンポーネントでしかstateを管理できませんでしたが、Hooksの登場で関数コンポーネントが現代Reactの標準となりました。
React Hooksのメリット:
・コードが簡潔で読みやすくなる(classの複雑な記法不要)
・ロジックの再利用がしやすい(カスタムフック)
・テストが書きやすい
・React公式のNext.js(App Router)でも全面採用
useState - 状態管理の基本
useStateはコンポーネントの状態を管理するための最も基本的なHookです。
基本的な使い方:
const [count, setCount] = useState(0);
// 配列分割代入で [現在の値, 更新関数] を受け取る
状態更新の注意点:
①stateは非同期で更新される(setCountの直後にcountを読んでも更新前の値)
②以前のstateを元に更新する場合は関数形式を使う:setCount(prev => prev + 1)
③オブジェクト・配列のstateはスプレッド構文でイミュータブルに更新する
const [user, setUser] = useState({ name: '', age: 0 });
setUser(prev => ({ ...prev, name: 'Taro' })); // NG: prev.name = 'Taro'
複雑なstateの管理:useState vs useReducer
複数の関連するstateがあり、更新ロジックが複雑になる場合はuseReducerの方が管理しやすくなります。状態遷移が明確で予測可能な設計ができます。
useEffect - 副作用処理の完全理解
useEffectはAPIフェッチ・タイマー・購読処理などの副作用を処理するHookです。正しく理解しないとバグの元になります。
useEffectの3つの動作パターン:
① 依存配列なし:毎レンダリング後に実行
useEffect(() => { ... });
② 空配列:マウント時のみ実行
useEffect(() => { ... }, []);
③ 依存配列あり:依存値が変わったら実行
useEffect(() => { ... }, [userId]);
クリーンアップ関数の重要性:
useEffectの内部でタイマー・購読・イベントリスナーを設定した場合は、returnでクリーンアップ関数を返してメモリリークを防ぎます。
よくある間違い:依存配列が不適切(eslint-plugin-react-hooksの警告を無視する)。useEffect内での状態更新が無限ループを引き起こすパターン。
useMemo・useCallback - パフォーマンス最適化
useMemoとuseCallbackはパフォーマンス最適化のためのHookです。ただし、過剰な使用はコードを複雑にするだけなので、実際にパフォーマンス問題がある場合のみ使いましょう。
useMemo:計算コストの高い処理の結果をメモ化します。依存値が変わらない限り再計算しません。
const expensiveValue = useMemo(() => heavyCalculation(input), [input]);
useCallback:関数をメモ化します。子コンポーネントへのコールバック関数の渡し方に使います。React.memoと組み合わせることで効果を発揮します。
const handleClick = useCallback(() => { doSomething(id); }, [id]);
カスタムフックの設計と実装
複数のコンポーネントで共通するロジックをカスタムフックとして切り出すことで、コードの再利用性が大幅に向上します。
よく使われるカスタムフックの例:
useFetch - データフェッチとローディング・エラー状態の管理
useLocalStorage - LocalStorageの読み書きを状態管理として扱う
useDebounce - 入力値のデバウンス処理
useWindowSize - ウィンドウサイズの取得と監視
useForm - フォームの状態管理・バリデーション
カスタムフックの命名規則:必ず「use」で始める(useXxx)。これはHooksのルール(条件分岐・ループ内での呼び出し不可等)をESLintが検出するために必要です。