Reactフック(Hooks)とは?全18種の一覧とReact Compiler時代の使い分け【2026年8月版】
Reactフックは、関数コンポーネントから状態や副作用といったReactの機能へ接続するための関数です。React 16.8で10種類から始まった仕組みは、2026年8月時点の最新版 react 19.2.8 で18種類まで増えました。同時に、React Compiler 1.0の登場で useMemo と useCallback を手で書く前提そのものが崩れています。この記事では、現行バージョンのフック全18種を一覧で整理したうえで、実装で使う順に使い方と判断基準をまとめます。
まとめ
react 19.2.8 が公開するフックは18種類です。react-dom 側の useFormStatus を足せば19種類、旧APIの useFormState まで数えれば20種類という数え方もできます。名前が似ている use は公式ドキュメントが「フックではない」と明記しているため、この18種には含めません。記事によってフックの総数が違うのは、この境界の引き方が違うためです。
使い分けの結論を先に書きます。状態は useState、状態遷移が3パターン以上に増えたら useReducer。副作用は useEffect ですが、データ取得は原則ライブラリに任せます。React 19.2で追加された useEffectEvent を使えば、依存配列に入れたくない処理をEffectの外へ逃がせます。そして React Compiler 1.0 を導入した環境では、useMemo・useCallback・React.memo の手書きは原則不要になりました。フックのルールにも「try/catch/finally の中で呼ばない」が明記されています。以降で、この判断の根拠を一次情報とコードで示します。
Reactフック全18種の一覧と分類
分類別の早見表
| 分類 | フック | 主な用途 | 追加バージョン |
|---|---|---|---|
| 状態 | useState | 状態の宣言と更新 | 16.8 |
| 状態 | useReducer | reducerで状態遷移を集約 | 16.8 |
| アクション | useActionState | アクションの実行状態を管理 | 19.0 |
| アクション | useOptimistic | 楽観的UIの一時状態 | 19.0 |
| コンテキスト | useContext | コンテキストの購読 | 16.8 |
| 参照 | useRef | 再レンダリングを起こさない値の保持 | 16.8 |
| 参照 | useImperativeHandle | refで公開する値の制御 | 16.8 |
| 副作用 | useEffect | 外部システムとの同期 | 16.8 |
| 副作用 | useLayoutEffect | 描画前のレイアウト計測 | 16.8 |
| 副作用 | useInsertionEffect | CSS-in-JSの動的挿入 | 18.0 |
| 副作用 | useEffectEvent | 依存配列に載せない処理の切り出し | 19.2 |
| 性能 | useMemo | 計算結果のキャッシュ | 16.8 |
| 性能 | useCallback | 関数定義のキャッシュ | 16.8 |
| 性能 | useTransition | 更新をノンブロッキング化 | 18.0 |
| 性能 | useDeferredValue | 非優先UIの更新を遅延 | 18.0 |
| その他 | useId | 一意なID生成 | 18.0 |
| その他 | useSyncExternalStore | 外部ストアの購読 | 18.0 |
| その他 | useDebugValue | DevTools表示ラベルの指定 | 16.8 |
react 19.2.8 が use で始まる名前で公開するエクスポートは19個で、フックではない use を除くと18種になります。react.dev のフックリファレンスに並ぶ数とも一致します。なお上表の分類列は読み進める順に整理した本記事独自のもので、react.dev は useActionState を「その他」に置いています。フォーム送信状態を読む useFormStatus だけは react ではなく react-dom から提供されます。同じく react-dom にある useFormState は useActionState に置き換わった旧APIなので、新規実装では使いません。
useがフック18種に入らない理由
Promiseやコンテキストを読み取る use は名前が use で始まりますが、公式リファレンスは「Despite its name, use is not a Hook.(名前に反して、useはフックではない)」と明記しています。実装上の違いははっきりしていて、「Unlike Hooks, it can be called inside loops and conditional statements like if.(フックと異なり、ループや if などの条件分岐の中で呼び出せる)」とされています。
つまりフックのルールが縛る「トップレベルでのみ呼ぶ」という制約を use は受けません。条件分岐でPromiseを出し分けたい場面ではこの差が効いてきます。Suspenseとの組み合わせや、クライアントコンポーネントでPromiseをキャッシュしないと再レンダリングのたびにフォールバックへ戻ってしまう落とし穴は、Reactのuseフック(use API)の使い方——React 19のPromise・Context読み取りを解説で個別に扱っています。
useStateとuseReducer:状態の宣言と切り替えの基準
useStateの基本と更新関数を使うべき場面
useState は const [値, 更新関数] = useState(初期値) の形で宣言し、状態変数と更新関数のペアを受け取るフックです。更新関数を呼ぶとコンポーネントが再レンダリングされます。つまずきやすいのは、同じイベント内で複数回更新するケースです。
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const addTwice = () => {
// 直前の値に依存する更新は、値ではなく更新関数を渡す
setCount(c => c + 1);
setCount(c => c + 1); // 2 増える。setCount(count + 1) を2回書くと 1 しか増えない
};
return <button onClick={addTwice}>{count}</button>;
}
setCount(count + 1) を2回書くと、どちらも同じレンダリング時点の count を参照するため1しか増えません。直前の値に依存する更新では必ず更新関数を渡します。
オブジェクト・配列の状態を壊さない更新の書き方
Reactは状態の変化を Object.is による参照比較で判定します。元のオブジェクトや配列を直接書き換えても参照が変わらないため、再レンダリングは起きません。
const [form, setForm] = useState({ name: '', email: '' });
// 既存プロパティを保ったまま1つだけ差し替える
setForm(prev => ({ ...prev, email: '[email protected]' }));
const [items, setItems] = useState([]);
// push は同じ配列参照を返すので再レンダリングされない。新しい配列を作る
setItems(prev => [...prev, newItem]);
フォームのように項目が10個を超えると、この展開が毎回のイベントハンドラに散らばって読みにくくなります。バリデーションも絡む規模なら、状態管理ごと React Hook Formとは?使い方・バリデーション・v7の書き方を実例で解説で扱っているようなフォーム専用ライブラリに寄せた方が保守しやすくなります。
useReducerへ切り替える判断基準
切り替えの目安は「状態遷移のパターンが3つ以上あり、しかも複数の状態が連動して変わるか」です。送信中・成功・失敗のように status と error が必ずセットで変わる場合、useState を2つ並べると片方だけ更新し忘れる不整合が起きます。
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'submitted':
return { status: 'sending', error: null };
case 'succeeded':
return { status: 'done', error: null };
case 'failed':
return { status: 'idle', error: action.message };
default:
throw new Error('unknown action: ' + action.type);
}
}
const [state, dispatch] = useReducer(reducer, { status: 'idle', error: null });
逆に、独立したboolean1つやテキスト入力1つに useReducer を使うのは冗長です。reducerの定義とアクション型の管理コストが、得られる見通しの良さを上回ります。アプリ全体でグローバルな状態を共有する段階まで来たら、Redux Toolkitとは?createSliceとRTK Queryの実装と採用判断【2026年8月版】で解説している専用ライブラリの導入を検討する時期です。
useEffectと副作用:クリーンアップとuseEffectEvent
useEffectの実行タイミングとクリーンアップ関数
useEffect はコンポーネントを外部システムへ接続するためのフックです。返り値のクリーンアップ関数は、アンマウント時だけでなく依存配列の値が変わる直前にも呼ばれます。
useEffect(() => {
const conn = createConnection(roomId);
conn.connect();
// 依存配列の値が変わる直前と、アンマウント時に呼ばれる
return () => conn.disconnect();
}, [roomId]);
この「変わる直前にも呼ばれる」性質が抜けていると、roomId が切り替わるたびに古い接続が残り続けます。開発環境のStrict Modeがマウントを2回実行するのは、まさにこのクリーンアップ漏れを検出するためです。
useEffectEventによる依存配列からの処理分離(React 19.2)
React 19.2(2025年10月1日リリース)で追加された useEffectEvent は、Effect内から呼ばれるが再実行のトリガーにはしたくない処理を切り出します。
import { useEffect, useEffectEvent } from 'react';
function ChatRoom({ roomId, theme }) {
// theme を読んでも Effect の再実行トリガーにはならない
const onConnected = useEffectEvent(() => {
showNotification('接続しました', theme);
});
useEffect(() => {
const conn = createConnection(roomId);
conn.on('connected', () => onConnected());
conn.connect();
return () => conn.disconnect();
}, [roomId]); // theme を依存配列に入れずに済む
}
従来は theme を依存配列に入れるとテーマ切り替えのたびに再接続が走り、外すとlintに警告されるというジレンマがありました。useEffectEvent でラップした関数は最新の値を読みつつ依存配列に載せずに済むため、この板挟みが解消します。19.2で入った他の変更はReact 19.2の新機能総まとめ:<Activity>コンポーネントやuseEffectEvent、cacheSignalなど注目ポイント徹底解説にまとめています。
データ取得をuseEffectで書かない判断
旧来の入門記事はデータ取得の例として useEffect の中で fetch を呼びます。この形は、競合状態・キャッシュ不在・重複リクエスト・エラー再試行を自前で書くことになり、実務では割に合いません。
クライアント側で取得するなら TanStack Queryとは?React Queryとの違い・v5の使い方と脆弱性対策のようなデータ取得ライブラリを使い、サーバー側で取得できるならReact Server Componentsに寄せます。useEffect を使うのは、WebSocket接続やイベントリスナー登録のように「外部システムとの同期」が本質である場面に絞ってください。
useContextとuseRef:値の共有と再レンダリングの回避
useContextによるprops受け渡しの省略
useContext は、propsを何階層も手渡しせずに値を配るためのフックです。React 19からはProviderを書かずコンテキスト自体をレンダーできるようになりました。公式リファレンスは「Starting in React 19, you can render <SomeContext> as a provider.」と記載しています。
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
// React 19 以降は Provider を書かずコンテキスト自体をレンダーできる
return (
<ThemeContext value="dark">
<Toolbar />
</ThemeContext>
);
}
function Toolbar() {
const theme = useContext(ThemeContext); // 直近の値を読む
return <button className={theme}>送信</button>;
}
注意点は、コンテキストの値が変わると購読している全コンポーネントが再レンダリングされることです。更新頻度の高い値と低い値を1つのコンテキストに詰め込むと、無関係なコンポーネントまで巻き込まれます。用途ごとにコンテキストを分けるのが基本方針です。
useRefが再レンダリングを起こさない理由
useRef が返すのは current プロパティを持つ可変オブジェクトです。この current を書き換えてもReactは変化を検知せず、再レンダリングは発生しません。
function EmailField() {
const inputRef = useRef(null);
const renderCount = useRef(0);
renderCount.current += 1; // 書き換えても再レンダリングは起きない
return <input ref={inputRef} type="email" />;
}
DOMノードの参照、タイマーIDの保持、前回値の記録がおもな用途です。画面に表示する値をrefへ入れると更新が反映されないので、表示に関わる値は useState を使います。子コンポーネントへrefを渡す方法はReact 19で変わり、forwardRef のラップが不要になりました。移行手順はReact 19でforwardRefが不要に|refをpropsで渡す新方式と移行手順で扱っています。
React Compiler 1.0で不要になるフックと、残るフック
自動メモ化が肩代わりする範囲
2025年10月7日(UTC)に babel-plugin-react-compiler の1.0.0が公開され、React Compilerは安定版になりました。これはビルド時にコンポーネントを解析して自動でメモ化するコンパイラで、公式ドキュメントは手書きの useMemo・useCallback・React.memo が不要になると説明しています。
ここは立場を明確にしておきます。2026年8月時点で新規にReactアプリを立ち上げるなら、React Compilerを入れて手書きメモ化を書かない方針を既定にすべきです。旧来の入門記事が紙幅を割いてきた「useCallbackで関数を固定し、React.memoで子の再レンダリングを防ぐ」という一連のテクニックは、コンパイラがある環境では書く必要がないうえ、依存配列の書き間違いというバグ源を持ち込みます。
Vite・Babelでの導入設定
npm install -D babel-plugin-react-compiler@latest
# Vite で reactCompilerPreset を使う場合は追加で必要
npm install -D @rolldown/plugin-babel
React 19との組み合わせが前提ですが、公式は「React Compiler is designed to work best with React 19, but it also supports React 17 and 18.」として17・18もサポート対象としています。Viteで reactCompilerPreset を使えるのは @vitejs/plugin-react の6.0.0以降で、6.0.0でインラインのBabelオプションが廃止されたため、上のように @rolldown/plugin-babel を別途入れます。
// vite.config.js
import { defineConfig } from 'vite';
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
import babel from '@rolldown/plugin-babel';
export default defineConfig({
plugins: [
react(),
babel({ presets: [reactCompilerPreset()] }),
],
});
仕組みと既存プロジェクトへの適用手順はReact Compilerとは?自動メモ化の仕組みと導入方法・useMemoとの違いを解説で詳しく扱っています。
それでも手書きメモ化が残る場面
コンパイラを入れても消えない用途はあります。第一に、コンパイラが解析を諦めたコンポーネントです。ルールに反する書き方が残っていると最適化がスキップされるため、その箇所は従来どおりの手当てが要ります。第二に、参照の同一性そのものが仕様として必要な場合です。useEffect の依存配列に渡すオブジェクトや、外部ライブラリへ渡すコールバックのように、「再生成されないこと」自体に意味がある値は明示的に固定します。
なお useTransition と useDeferredValue は分類こそ性能系ですが、メモ化とは別物なのでコンパイラを入れても不要になりません。これらは重い更新の優先度を下げる仕組みで、代替になるものがありません。
フックのルールとeslint-plugin-react-hooks 7系
呼び出してよい場所と、してはいけない場所
フックは関数コンポーネントかカスタムフックの本体で、トップレベルからのみ呼び出せます。公式が禁止として挙げているのは次の6つです。
- 条件分岐やループの中
- 条件付き
returnより後 - イベントハンドラの中
- クラスコンポーネントの中
useMemo・useReducer・useEffectへ渡す関数の中try・catch・finallyブロックの中
最後の try/catch/finally 禁止は、2019年前後に書かれた解説記事にはまず載っていません。フックの呼び出し順序が実行経路によってずれる可能性があるためで、エラー処理は use やエラーバウンダリ側で扱います。
7系のプリセットとコンパイラ由来のlint
eslint-plugin-react-hooks は7.0.0でプリセットを整理し、-legacy が付く旧形式向けの設定を廃止しました。7.1.1が実際に公開している設定は recommended、recommended-latest、そして両者を格納した flat の3つです。ここに落とし穴があります。フラットコンフィグから読み込むのは configs.recommended ではなく configs.flat.recommended です。前者は plugins を配列で持つ .eslintrc 形式のままなので、そのまま eslint.config.js に置くと読み込み時にエラーになります。公式READMEが案内しているのも flat 経由の書き方です。
// eslint.config.js
import reactHooks from 'eslint-plugin-react-hooks';
export default [
// フラットコンフィグでは configs.recommended ではなく configs.flat.recommended を使う
// (configs.recommended は .eslintrc 形式のままなので読み込むとエラーになる)
reactHooks.configs.flat.recommended,
];
7系で大きいのは、React Compiler由来のルールが既定で有効になった点です。set-state-in-effect(Effect内での状態更新)、set-state-in-render(レンダー中の状態更新)、purity(副作用のある式)、immutability、refs といった検査が加わり、従来の rules-of-hooks と exhaustive-deps だけでは拾えなかった問題を静的に検出できます。recommended が有効化するルールは合計16本。従来の2本から14本増えた計算なので、既存プロジェクトに入れれば相応の指摘が出ます。その多くはコンパイラが最適化を諦める箇所と重なるため、先に潰しておく価値があります。コードベース全体の健全性を機械的に見たい場合はReact Doctorとは?npxで使うReactコード診断ツールの使い方・スコア・ESLintとの違いも併用できます。
React 16.8から19.2までのフック追加履歴
フックがどのバージョンで何を解決するために増えてきたかを押さえておくと、記事や社内コードの前提バージョンを判断しやすくなります。
| バージョン | 時期 | 追加されたフック | 背景 |
|---|---|---|---|
| 16.8 | 2019年2月 | useState / useEffect / useContext / useReducer / useRef / useMemo / useCallback / useImperativeHandle / useLayoutEffect / useDebugValue | 関数コンポーネントで状態とライフサイクルを扱う |
| 18.0 | 2022年3月 | useTransition / useDeferredValue / useId / useSyncExternalStore / useInsertionEffect | 並行レンダリングとSSRのhydration対応 |
| 19.0 | 2024年12月 | useActionState / useOptimistic | Actionsによるフォーム送信の標準化 |
| 19.2 | 2025年10月 | useEffectEvent | 依存配列に載せない処理の分離 |
16.8のフック追加から7年が経ち、クラスコンポーネント前提のコードは実質的に保守対象のみになりました。18から19への移行時の変更点はReact 19とは?18からの変更点・新機能とReact Compiler・最新バージョンを解説にまとめています。
よくある質問
Q. Reactフックは全部で何種類ありますか。
A. 2026年8月時点の最新版 react 19.2.8 が公開するフックは18種類です。react-dom の useFormStatus を含めると19種類になります。use は公式が「フックではない」としているため、この数には含めていません。
Q. useStateとは何ですか。
A. コンポーネントに状態変数を持たせるフックです。const [値, 更新関数] = useState(初期値) の形で宣言し、更新関数を呼ぶとコンポーネントが再レンダリングされます。直前の値をもとに更新する場合は、値ではなく更新関数を渡してください。
Q. React 16.8より前のバージョンでフックは使えますか。
A. 使えません。フックは16.8で追加された機能で、それ以前のバージョンでは状態やライフサイクルをクラスコンポーネントで書く必要があります。なおReact Compilerが対応するのは17以降です。
Q. React Compilerを導入したら、既存のuseMemoとuseCallbackは削除すべきですか。
A. 一括削除は避けてください。コンパイラが最適化を適用できたかはビルド時に確認でき、適用された箇所から段階的に外すのが安全です。参照の同一性が仕様として必要な箇所は残します。
Q. カスタムフックはどこから作るべきですか。
A. 同じ useState と useEffect の組み合わせが2箇所以上に現れた時点が目安です。名前は use で始める必要があり、この命名規則によってlintがフックのルールを適用できるようになります。