React Hooksは名前が use で始まる関数で、関数コンポーネントがReactの機能を使えるようにします。値を覚えておく useState、レンダリングの後にコードを実行する useEffect、DOMノードを持っておく useRef、共有データを読む useContext などです。コンポーネントの先頭で呼ぶと、Reactはレンダリングの間でその値を保ちます。
ここでは4つのフックが一緒に動いています。useState がテキストを保存し、useRef が入力欄を指してボタンがフォーカスできるようにし、useMemo が検索語が変わるまでフィルター済みのリストを保ち、useEffect が検索語が変わったレンダリングの後にログを出します。an と入力してコンソールを見てください。リストが更新された後、キーを押すごとに1行ずつ出ます。
フックが存在する理由
React 16.8より前は、stateやライフサイクルのコードが必要なコンポーネントはクラスでなければなりませんでした。1つの機能のロジックが componentDidMount、componentDidUpdate、componentWillUnmount に分かれ、それをコンポーネント間で共有するには、ミックスイン(クラス構文では一度も動きませんでした)、高階コンポーネント、レンダープロップを使う必要があり、どれもツリーを余分な層で包むものでした。
// The class way: one feature, three methods
class Clock extends React.Component {
state = { now: new Date() };
componentDidMount() {
this.id = setInterval(() => this.setState({ now: new Date() }), 1000);
}
componentWillUnmount() {
clearInterval(this.id);
}
render() {
return <p>{this.state.now.toLocaleTimeString()}</p>;
}
}
フックなら同じ機能が1か所にまとまります。エフェクトがタイマーを始め、そのクリーンアップが止めます。
時計を隠すと、コンソールに timer stopped と出ます。Clock が画面から消えたときにReactがクリーンアップを実行したのです。もう一度表示すると、新しいタイマーが始まります。クラスコンポーネントはReact 19でも動きますが、新しいコードではフックを使います。
すべての組み込みフック
React 19.2のフックは、コンポーネントに何を与えるかでグループ分けできます。最初の2つのグループは毎日使い、それ以外は特定の問題が起きたときに使います。
| フック | 与えてくれるもの | ページ |
|---|---|---|
useState | レンダリングをまたいで残る値と、再レンダリングを起こすセッター | useState |
useReducer | reducer関数とdispatchされたアクションで更新されるstate | useReducer |
useContext | propsを渡さずに、親が提供する値 | useContext |
useRef | レンダリングをまたいで残る変更可能な箱。DOMノードによく使う | useRef |
useImperativeHandle | 親が自分のrefを通じて何を見るかを選ぶ | forwardRef |
useEffect | 通常は描画の後に実行されるコード:タイマー、購読、データ取得 | useEffect |
useLayoutEffect | DOMの更新後、描画の前に実行されるコード | useLayoutEffect |
useInsertionEffect | レイアウトエフェクトより前に実行される。CSS-in-JSライブラリ用 | |
useEffectEvent | エフェクトから呼べて、常に最新のpropsとstateを見る関数 | useEffect |
useMemo | 計算した値をレンダリング間でキャッシュする | useMemo |
useCallback | 関数をレンダリング間でキャッシュする | useCallback |
useTransition | 更新を緊急でないものとして扱い、保留中かどうかを教える | useTransition |
useDeferredValue | 重いレンダリングの間は遅れてついてくる値のコピー | useDeferredValue |
useId | サーバーとクライアントで一致する一意のID | useId |
useSyncExternalStore | Reactの外にあるストアを購読する | useSyncExternalStore |
useDebugValue | React DevToolsでカスタムフックに付けるラベル | |
use | Promiseやコンテキストを読む。条件分岐の中に置ける | use |
useActionState | フォームアクションが更新するstateと、保留中フラグ | useActionState |
useOptimistic | サーバーが応答する前に、予想される結果を表示する | useOptimistic |
useFormStatus | 親フォームの保留中の状態(react-dom から) |
use、useActionState、useOptimistic、useFormStatus はReact 19で登場し、useEffectEvent は19.2で安定版になりました。一覧のそれ以外のフックはすべてReact 18でも動きます。
stateはレンダリングを起こし、refは起こさない
すべてのフックがレンダリングを起こすわけではありません。useState と useReducer は起こします。値を変えると、Reactはコンポーネントをもう一度描画します。useRef は current フィールドを自由に変えられるオブジェクトを渡し、Reactはそれが原因で再レンダリングすることはありません。そのため、タイマーのID、前回の値、画面に表示しないカウントを置くのに適しています。
useReducer がカートを、useState がメモを持っています。どちらも変わるとレンダリングを起こし、エフェクトはレンダリングごとに1行ログを出します。エフェクトは commits.current も変えますが、その変更が自分でレンダリングを起こすことはないので、ログはループしません。カウントをコンポーネント本体ではなくエフェクトで更新しているのは、本体はレンダリング中に何も変えるべきではないからです。
フックのルール
すべてのフックは2つのルールに従います。
- フックはコンポーネントのトップレベルで呼び、条件分岐、ループ、ネストした関数の中では決して呼ばない。
- フックは関数コンポーネントか、自作のカスタムフックからだけ呼ぶ。
Reactはフックを名前で区別していません。呼び出しの順番で区別し、その順番がすべてのレンダリングで同じであることを期待しています。if の中のフックは、その後のすべてのフックをずらしてしまいます。何が壊れ、どう直すかはフックのルールのページで紹介しています。use は唯一の例外で、条件分岐の中で呼べます。
最初のカスタムフック
2つのコンポーネントが同じstateを持つロジックを必要とするなら、それを名前が use で始まる関数に移します。その関数はほかのどんなフックでも呼べます。それを呼ぶ各コンポーネントは、自分のstateを持ちます。
どちらのカウンターも同じフックを実行していますが、一方をクリックしてももう一方は変わりません。カスタムフックが共有するのはロジックであって、stateではないのです。useCounter に decrement 関数と、それを呼ぶボタンを追加すると、両方のカウンターに一度に反映されます。ほかのパターン(useToggle、useDebounce、useLocalStorage)はカスタムフックのページにあります。
どのフックを使うか
- 値が変わったら画面も変わるべき:
useState、多くのイベントが同じstateを更新するならuseReducer。 - Reactの外にあるもの(タイマー、購読、リクエスト)とやり取りする:
useEffect。 - DOMノードや、画面に表示しない値が必要:
useRef。 - ツリーの深いところにある多くのコンポーネントが同じ値を必要とする:
useContext。 - 1つの計算や、メモ化された子の再レンダリングのせいでレンダリングが遅い:
useMemoとuseCallback。React Compilerがこのメモ化を代わりに追加してくれますが、手で書く方法も今も動き、よく使われています。 - 裏の更新が重くて入力がもたつく:
useTransitionかuseDeferredValue。
よくある質問
Reactのフックとは何ですか?
フックは名前が use で始まる関数で、関数コンポーネントがReactの機能を使えるようにします。stateには useState、副作用には useEffect、コンテキストには useContext、レンダリングを起こさずにレンダリングをまたいで残る値には useRef などがあります。
Reactにフックが追加されたのはなぜですか?
フック以前(React 16.8より前)は、stateとライフサイクルメソッドはクラスコンポーネントにしかなく、stateを持つロジックを共有するにはミックスイン、高階コンポーネント、レンダープロップが必要でした。フックはそのロジックを、どの関数コンポーネントからも呼べて、カスタムフックとして共有できる普通の関数にまとめます。
Reactにはいくつのフックがありますか?
React 19.2では react パッケージに約20個の組み込みフックがあり、さらに react-dom に useFormStatus があります。ほとんどのアプリが日常的に使うのは、useState、useEffect、useRef、useContext、useMemo、useCallback などのいくつかです。
クラスコンポーネントでフックを使えますか?
いいえ。フックが動くのは関数コンポーネントとほかのフックの中だけです。それでも関数コンポーネントの隣にクラスコンポーネントを描画できますし、クラスがフックを使う関数コンポーネントを描画することもできます。
カスタムフックとは何ですか?
名前が use で始まり、ほかのフックを呼ぶ自作の関数です。複数のコンポーネントが同じstateを持つロジックを再利用でき、それを呼ぶ各コンポーネントは別々のstateを持ちます。