Reactのuseフック(use API)の使い方——React 19のPromise・Context読み取りを解説
React 19で追加されたuseは、Promiseやコンテクストの値をレンダー中に読み取るためのAPIです。名前に反してフックではなく、条件分岐やループの中でも呼べる点が従来のフックと大きく異なります。この記事では、use(resource)の基本構文から、useEffectを使わないデータ取得、Suspense・Error Boundaryとの連携、Promiseキャッシュの必須ルールや制約までをコード例つきで整理します。フック全体の入門はReactフックの基本と導入、React 19のそのほかの変更点はReact 19とは?18からの変更点・新機能の解説を参照してください。
まとめ
- useはPromiseとContextを読む。Promiseを渡すと解決までコンポーネントがサスペンドし、Contextを渡すとuseContextと同じ値を返す。
- フックではないため条件分岐・ループ内で呼べる。これがuseContextやuseEffectにない最大の利点。
- データ取得はSuspenseで待ち、エラーはError Boundaryで捕捉する。
useはtry/catchの中では使えない。 - クライアントで渡すPromiseはキャッシュ必須。レンダー内で毎回
fetch()を呼ぶと再レンダーのたびにフォールバックへ戻る。 - 正式版はReact 19.0(2024年12月)。最新は19.2系(バージョンはReact 19.2の新機能まとめで確認)。
useフックとは——React 19で追加されたuse APIの基本
useは、リソース(PromiseまたはContext)から値を読み取るReact 19の新APIです。const 値 = use(リソース)と書くだけで、非同期データやコンテクストをレンダー中に同期的なコードのように扱えます。公式ドキュメントではHooksの章に載りますが、名前に反してHookそのものではなく、後述のとおり呼び出し位置の制約はフックより緩いのが特徴です。
use(resource)の構文と読み取れる対象
useが受け取れるのは次の2種類です。ほかの値を渡すことはできません。
| 渡すもの | 挙動 | 従来の代替 |
|---|---|---|
| Promise | 解決までサスペンド、解決値を返す | useEffect+useState |
| Context | 最も近いProviderの値を返す | useContext |
import { use } from 'react';
function Message({ messagePromise }) {
const text = use(messagePromise); // Promiseの解決値を読む
return <p>{text}</p>;
}
useが「フックではない」理由と条件分岐・ループ内呼び出し
useStateやuseEffectは、レンダーのたびに同じ順序・同じ回数で呼ばれる前提のため、if文やループの中では呼べません。useはこの制約を受けず、条件分岐やループの内側で呼べます。これにより「特定の条件のときだけコンテクストを読む」といった書き方が自然に表現できます。
function Heading({ children, show }) {
if (show) {
// useはif文の中でも呼べる(useContextは不可)
const theme = use(ThemeContext);
return <h1 style={{ color: theme.color }}>{children}</h1>;
}
return null;
}
use(Promise)でデータを取得する——useEffectなしの非同期フェッチ
Promiseをuseに渡すと、Reactはその解決を待つ間コンポーネントをサスペンドさせ、解決後に解決値でレンダーし直します。useEffect+useStateでローディング用のstateを手書きする定型が不要になり、データ取得のコードが宣言的になります。
import { use } from 'react';
function Albums({ albumsPromise }) {
const albums = use(albumsPromise); // 解決までサスペンド
return (
<ul>
{albums.map(a => <li key={a.id}>{a.title}</li>)}
</ul>
);
}
Suspenseでローディング表示を出す
サスペンド中に表示する内容は、useを呼ぶコンポーネントを<Suspense>で囲み、fallbackに渡します。ローディング状態をisLoadingのようなstateで管理する必要はありません。
function Page({ albumsPromise }) {
return (
<Suspense fallback={<p>読み込み中…</p>}>
<Albums albumsPromise={albumsPromise} />
</Suspense>
);
}
Error Boundaryでエラーを捕捉する(try/catchは不可)
Promiseがrejectされた場合、エラーは最も近いError Boundaryに伝播します。useはtry/catchブロックの中では呼べないため、例外処理はError Boundaryで行うか、Promiseに.catch()で代替値を用意します。公式ドキュメントも「try/catchの代わりにError Boundaryで囲むこと」と明記しています。
// NG: useはtry/catchの中で使えない
// OK: 代替値を .catch で用意しておく
// ※ この .catch もレンダー外(キャッシュ側)で行い、毎レンダー生成を避ける
const safePromise = albumsPromise.catch(() => []);
const albums = use(safePromise);
Promiseのキャッシュが必須——毎レンダー生成の罠
useに渡すPromiseは、再レンダーをまたいで同じインスタンスが使い回される必要があります。レンダー関数の中で直接fetch()を呼ぶと、レンダーのたびに新しいPromiseが生成され、Reactは毎回サスペンドしてフォールバックへ戻り続けます。
| 書き方 | 結果 |
|---|---|
レンダー内で use(fetch(url)) |
再レンダーごとに再サスペンド(NG) |
| キャッシュ済みPromiseを渡す | 解決値を安定して返す(OK) |
クライアントコンポーネントでは、Promiseを親から受け取る、あるいはSuspense対応のデータ取得ライブラリのキャッシュ経由で渡すのが安全です。サーバーコンポーネントから渡す場合は、解決値がシリアライズ可能である必要があります。
use(Context)でコンテクストを読む——useContextとの使い分け
Contextを渡すと、useは最も近いProviderの値を返します。挙動はuseContextと同じですが、条件分岐やループの内側で呼べる分だけ柔軟に使えます。ただしサーバーコンポーネントではuseによるコンテクスト読み取りはサポートされません。
function Button() {
const theme = use(ThemeContext); // useContextの置き換え
return <button className={theme}>送信</button>;
}
useを避けるべき場面と現時点の制約
useは万能ではありません。次のケースでは従来のフックやフレームワークの機構を使うべきです。
- クライアントで自前のfetchを直接渡す用途:キャッシュを自前で用意しない限り再サスペンドする。データ取得はSuspense対応ライブラリやフレームワーク(サーバーコンポーネントからのPromise受け渡し)に任せるのが安全。
- 副作用(購読・ログ送信・DOM操作):useは値の読み取り専用。副作用は引き続き
useEffectが担う。 - サーバーコンポーネントでのContext読み取り:非対応。この用途ではpropsで値を渡す。
- エラーを局所的にtry/catchで拾いたい場合:不可。Error Boundaryか
.catch()へ設計を寄せる。
つまりuseは「useEffect+useStateのデータ取得定型」と「useContext」を置き換えるAPIであり、副作用フックを不要にするものではないと理解するのが実務的です。
useと合わせて使うフォーム・アクション系フック
React 19では、フォーム送信やアクション(Actions)の状態管理を簡素化するフックが整いました。useActionState・useFormStatus・useOptimisticはReact 19で追加されたフックで、useTransitionはReact 18で追加済みのフックがReact 19で非同期関数に対応したものです。詳細はReact 19の新機能まとめを参照してください。
| フック | 役割 | 追加 |
|---|---|---|
| useActionState | アクションのpending/成功/エラーを1つのstateで追跡 | React 19 |
| useFormStatus | 親フォームの送信状態(pending等)を子から参照 | React 19 |
| useOptimistic | 非同期完了前に楽観的なUIを即時表示 | React 19 |
| useTransition | 非同期関数をトランジションとして扱いisPendingを自動管理 | React 18(19で非同期対応) |
Reactビルトインフック早見一覧
useを含むReactの主なビルトインフックを役割別に整理します。個々のフックの詳細はReactフックの基本と導入で解説しています。
| 分類 | フック | 用途 |
|---|---|---|
| 状態 | useState / useReducer | コンポーネントの状態管理 |
| コンテクスト | useContext / use | Providerの値を読む(useは条件分岐可) |
| 参照 | useRef / useImperativeHandle | DOMや可変値の保持 |
| 副作用 | useEffect / useLayoutEffect / useInsertionEffect | 購読・DOM同期・スタイル挿入 |
| パフォーマンス | useMemo / useCallback / useDeferredValue / useTransition | 再計算・再レンダーの最適化 |
| 非同期・アクション | use / useActionState / useOptimistic / useFormStatus | Promise読み取り・フォーム処理(React 19) |
| その他 | useId / useSyncExternalStore / useDebugValue | ID生成・外部ストア購読・デバッグ |
よくある質問
useはReactのどのバージョンから使えますか?
React 19.0(2024年12月正式リリース)から利用できます。18以前には存在しません。最新の安定版は19.2系で、バージョンごとの差分はReact 19.2の新機能まとめで確認してください。
useとuseContextはどちらを使うべきですか?
コンテクストを条件分岐やループの中で読みたい場合はuseが適しています。それ以外はどちらでも動作し、より柔軟に使えるのがuseです。ただしサーバーコンポーネントでのコンテクスト読み取りはuse非対応です。
useを使えばuseEffectは不要になりますか?
いいえ。useが置き換えるのは「useEffectで書いていたデータ取得の定型」であり、購読やDOM操作などの副作用は引き続きuseEffectが担います。データ取得以外の副作用まで無理にuseへ寄せる必要はありません。
use(fetch(url))と書いてもよいですか?
クライアントコンポーネントでは避けてください。レンダーのたびに新しいPromiseが生成され、再レンダーごとにSuspenseのフォールバックへ戻り続けます。Promiseは親から受け取るか、キャッシュ経由で同じインスタンスを渡します。
useのエラーはtry/catchで拾えますか?
拾えません。useはtry/catchブロックの中では呼べない仕様です。エラーは最も近いError Boundaryで捕捉するか、Promiseに.catch()を付けて代替値を用意します。