Hooksの使い分け — 判断フローと横断比較
この章の目次開く
ここまで7つのフックを個別に学んできました。 この章では全体を俯瞰して、「この場面ではどのフックを使うべきか」を迷わず判断できるようにします。
学習者フックが7つも出てきて頭がごちゃごちゃ…。結局どの場面でどれを使えばいいの?
7つのフックの横断比較
各フックの性質を整理します。
useState — UIに影響する値を管理する。値を変更すると再レンダーが走り、画面が更新される。
useContext — Providerがサブツリーへ提供した値を読み取る。テーマやログインユーザーなど、離れた複数のコンポーネントで共有する値に使う。
useRef — UIに影響しない値を保持する。DOM参照、タイマーID、前回の値など。変更しても再レンダーは起きない。
useEffect — レンダー後に外部と同期する。API呼び出し、購読、タイマーなど。クリーンアップ関数で後始末ができる。
useMemo — 重い計算結果をキャッシュする。依存が変わらない限り前回の結果を返す。レンダー中に同期実行。
useCallback — 関数オブジェクトをキャッシュする。useMemoの関数特化版。React.memoされた子コンポーネントへのpropsや、useEffectの依存配列で参照を安定させたいときに使う。
useTransition — state更新の一部を緊急ではない更新としてマークする。入力操作などを優先し、重い一覧やタブ内容のレンダーを中断可能にする。
判断フローチャート
「値を持ちたい」「値を共有したい」「処理を実行したい」「パフォーマンスを改善したい」という4つの出発点から、どのフックに辿り着くかを示します。
値を持ちたい場合
値を共有したい場合
処理を実行したい場合
子コンポーネントへの受け渡しを最適化したい場合
重い画面更新でも操作を止めたくない場合
よくある疑問

useStateとuseContextはどう使い分ける?
useState は値を保持して更新するフックです。useContext は、上位のProviderが持つ値を離れたコンポーネントから読み取るフックです。
値を実際に所有するのは useState を呼び出したコンポーネントで、Contextはその値を配下へ届けます。ローカルな値なら useState だけで十分です。サブツリー内の離れた複数箇所で同じ値を使う必要が出たときに、Contextとの組み合わせを検討します。
useMemoとuseCallbackはどう使い分ける?
メモ化したい対象が「値」なら useMemo、「関数」なら useCallback です。useCallback は useMemo の関数特化版なので、useMemo(() => () => { ... }, [deps]) と書けば useCallback と同じことができますが、意図の明確さから関数には useCallback を使います。
useRefとuseMemoの違いがわからない
useRef は自分で .current を書き換えるまでずっと同じ値を持ち続けます。useMemo は依存配列が変わったら自動で再計算します。
「タイマーIDを保持する」→ 自動再計算は不要 → useRef。
「ユーザーリストをソートした結果を保持する」→ 元データが変わったら再計算 → useMemo。
useEffectとuseMemoは両方とも依存配列があるけど何が違う?
実行タイミングが異なります。useMemo はレンダー中に同期的に実行され、すぐに値を返します。useEffect はレンダーが完了してDOMに反映された後に実行されます。
「ソートした結果を今すぐJSXで使いたい」→ useMemo。
「APIからデータを取得したい」→ useEffect。
useCallbackを使っているのにパフォーマンスが改善しない
学習者useCallback を使ってるのに全然速くならない…。何が足りないの?
先生受け取る側の子コンポーネントが React.memo でラップされているか確認しよう。useCallback 単体ではパフォーマンスに影響しない。参照の安定性を「活かす側」がいて初めて効果があるよ。
受け取る側の子コンポーネントが React.memo でラップされていない可能性が高いです。useCallback 単体では効果がなく、参照の安定性を活用する側(React.memo、useEffect の依存配列)があって初めて意味を持ちます。
useMemoとuseTransitionはどう使い分ける?
useMemo は、同じ依存値に対する計算結果を再利用して、計算のやり直しを減らします。useTransition は1回分の処理自体を軽くせず、後回しにできる画面更新の優先度を下げます。
「同じ条件の重い計算を繰り返している」→ useMemo。
「重い一覧の更新中も入力やクリックへ反応したい」→ useTransition。
どちらも必要な場合はありますが、目的は別です。まず遅い場所を計測し、計算の重複を減らしたいのか、操作の応答性を保ちたいのかで判断します。
カスタムフックへの導線
7つのフックを使う処理が複数のコンポーネントで重複するようになったら、カスタムフックとして切り出せます。
// useWindowSize — ウィンドウサイズを監視するカスタムフック
function useWindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
handleResize(); // 初期値を設定
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
// 使う側
function Header() {
const { width } = useWindowSize();
return <header>{width < 768 ? 'モバイル' : 'デスクトップ'}</header>;
}カスタムフックは use で始まる関数で、中で他のフックを自由に使えます。「イベントリスナーの登録(useEffect)+ 値の管理(useState)」のような定型パターンを1つの関数にまとめられます。
カスタムフック自体は本書のスコープ外ですが、7つのフックを理解していれば、既存のカスタムフックのコードを読んだときに「ああ、useEffectで購読してuseStateで値を管理しているのか」と構造がわかるようになります。
まとめ
7つのフックはそれぞれ異なる役割を持っています。
useState はUIに影響する状態を管理し、useContext はProviderが提供した共有値を読み取ります。useRef はUIに影響しない値を再レンダーなしに保持します。useEffect はレンダー後に外部との同期処理を実行します。useMemo は重い計算結果をキャッシュし、useCallback は関数オブジェクトをキャッシュします。useTransition は後回しにできる更新の優先度を下げ、緊急な操作への応答を保ちます。
これでReactのHooksの土台は固まりました。この先Next.jsなどのフレームワークに進むと、Server ComponentやApp Routerなど新しい概念が出てきますが、それらの理解もここで学んだHooksの知識が基盤になります。