React 19.2は2025年10月1日にnpmで公開されたマイナーリリースです。画面の一部を状態ごと隠す <Activity>、Effectから呼ぶイベント処理を依存配列から切り離す useEffectEvent、Server Components用の cacheSignal、ChromeのPerformanceパネルに出るPerformance Tracks、静的部分を先に作るPartial Pre-renderingが入りました。
19.2系のパッチは2026年7月21日の19.2.8まで出ています。2026年9月9日には19.3.0が公開されました。Reactの最新バージョンと18からの変更点はReact 19とは?18からの変更点・新機能と最新バージョンの解説で扱っています。この記事は19.2で入った機能に絞り、react/react-dom 19.2.8と19.3.0をNode.js 26.5.0とjsdomで動かした結果を載せます。
まとめ:React 19.2で押さえる要点
<Activity mode="hidden">は子のEffectを片付け、DOMをdisplay: noneで隠し、stateを残します。表示に戻すとEffectが再実行されます。useEffectEventで作った関数は依存配列に入れず、Effectの中からだけ呼びます。レンダー中に呼ぶと実行時エラーになります。- 19.2系では、
memo・forwardRefで包んだコンポーネント内のuseEffectEventがContextの古い値を読みます。19.2.8でも再現し、修正は19.3.0に入りました。 cacheSignalはServer Components専用です。Client Componentsでは常にnullを返します。- 19.2.1〜19.2.8の8本はすべてReact Server Componentsの修正です。RSCを使う構成でDoS対策まで入っているのは19.2.4以降です。
- 互換性に効く変更は
useIdの形式(«r0»から_r_0_)と、ESLintプラグインの既定がflat configになった点です。
以下、機能の一覧、各APIの使い方と実行結果、SSRまわりの変更、19.2.xのパッチ、19.3へ上げる判断の順に説明します。
React 19.2で追加された機能の一覧
| 機能 | パッケージ | 使える場所 | 役割 |
|---|---|---|---|
<Activity> |
react | クライアント・SSR | 状態を残して隠す |
useEffectEvent |
react | Effectの中 | 最新値を読むイベント関数 |
cacheSignal |
react | Server Componentsのみ | cache終了でAbortSignal発火 |
| Performance Tracks | react-dom | 開発・プロファイリングビルド | DevToolsに専用トラック |
resume など計4API |
react-dom | サーバー | Partial Pre-rendering |
| Suspenseのバッチ表示 | react-dom | ストリーミングSSR | 表示をまとめて行う |
| Node.jsでWeb Streams | react-dom | Node.js | renderToReadableStream 等が利用可 |
19.1.9をインストールして確かめると、Activity も useEffectEvent も react からexportされていません。useEffectEvent を呼ぶと TypeError: ... useEffectEvent is not a function で止まります。上の機能を使うには19.2.0以上が必要です。
条件付きレンダリング({isVisible && <Page />})で消すと、コンポーネントはアンマウントされ、入力途中の値も消えます。<Activity> に置き換えると、隠している間もstateとDOMが残ります。mode は 'visible' と 'hidden' の2つで、省略すると 'visible' です。
import { Activity, useEffect, useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('effect mount');
return () => console.log('effect cleanup');
}, []);
return (
<>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>加算</button>
</>
);
}
export function Tab({ isVisible }) {
return (
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<Counter />
</Activity>
);
}
19.2.8で、countを5にしてから hidden に切り替えると、effect cleanup が出力され、<span> は <span style="display: none !important;">5</span> になりました。visible に戻すと effect mount が再び出て、表示は5のままです。19.3.0でも同じ結果でした。Effectは止まり、stateとDOMは残る、という動きです。
Activityで隠すときに注意が要る子コンポーネント
DOMそのものが副作用を持つ子は、隠されることを前提にクリーンアップを書く必要があります。hidden はDOMを破棄しないため、<video> を再生したまま隠すと音声が流れ続けます。React公式ドキュメントのトラブルシューティングはこの例を挙げ、Effectのクリーンアップで pause() を呼ぶ対処を示しています。ほかに注意点が2つあります。テキストだけを返す子は、隠す要素が無いため hidden の間は何も出力されません。隠した状態での事前読み込みは、use で読むPromiseのようにSuspenseを起動するデータだけが対象で、Effectの中のfetchは先読みされません。
useEffectEventの使い方:Effectの依存配列から外す値の書き分け
useEffectEvent は、Effectから呼ばれる「イベント」部分を切り出すフックです。React公式ブログの例では、チャットルームの接続通知に使う theme が依存配列に入っているため、テーマを変えるだけで再接続が起きていました。
import { useEffect, useEffectEvent } from 'react';
function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('Connected!', theme);
});
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]);
}
onConnected は呼ばれた時点の最新の theme を読みます。依存配列は roomId だけになり、テーマを変えても再接続しません。ただし公式ドキュメントは、依存配列の警告を黙らせる目的で使うことを禁じています。Effectから発火する「イベント」と呼べる処理にだけ使います。
ESLintが出す警告とエラーの文言
使い方の誤りは eslint-plugin-react-hooks が検出します。7.1.1(2026年4月17日公開)とESLint 10.11.0で、誤った使い方を2つ書いて実行した結果は次のとおりです。
- 依存配列に入れた場合(
exhaustive-depsの警告):Functions returned from `useEffectEvent` must not be included in the dependency array. Remove `onConnected` from the list onClickから呼んだ場合(rules-of-hooksのエラー):`onConnected` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component
ESLintを通さずにレンダー中に呼ぶと、実行時に A function wrapped in useEffectEvent can't be called during rendering. が投げられます(19.2.8・19.3.0とも同じ文言です)。返り値の関数はレンダーごとに作り直されるため、子コンポーネントへpropsで渡す使い方もできません。
memoとforwardRefの中では古い値を読む不具合
19.2系には、memo または forwardRef で包んだコンポーネントの useEffectEvent が、Contextの更新を反映しない不具合があります(GitHub issue #34818、修正はPR #34831)。次は検証コードの抜粋です。外部変数への代入と外部からの呼び出しは不具合観測用であり、通常の実装ではEffect内に呼び出しを閉じます。
const Ctx = createContext('POP');
let handler;
const Child = memo(function Child() {
const nav = useContext(Ctx);
const onTick = useEffectEvent(() => nav);
useEffect(() => { handler = onTick; }, []);
return <p>{nav}</p>;
});
// Providerの値を 'POP' から 'REPLACE' へ更新した後に handler() を呼ぶ
19.2.8では、画面は REPLACE を表示しているのに handler() は POP を返しました。memo を外した同じコンポーネントでは REPLACE を返します。19.3.0では、memo ありでも REPLACE でした。修正は2025年10月13日にマージされましたが、19.2.1以降のパッチには入っていません。19.2系のまま使うなら、memo の中ではContextの値を useEffectEvent 経由で読まない書き方にします。
cacheSignalの使い方:Server Componentsのキャッシュ終了時の処理中断
cacheSignal() は、cache() の寿命が終わったときにabortされる AbortSignal を返します。寿命が終わるのは、レンダーが完了したとき、中断されたとき、失敗したときです。fetch に渡しておくと、使われなくなったリクエストを止められます。
import { cache, cacheSignal } from 'react';
const dedupedFetch = cache(fetch);
async function Component() {
await dedupedFetch(url, { signal: cacheSignal() });
}
使えるのはServer Componentsだけです。Client Componentsでは常に null が返り、レンダーの外で呼んだ場合も null です。null を返すのは、その範囲がキャッシュされていないことを示すためだと公式ドキュメントは説明しています。Server Componentsの境界と書き方はReact Server Components(RSC)の解説を参照してください。
Performance Tracksの見方:Chromeに追加されるSchedulerとComponents
19.2から、ChromeのDevToolsでPerformanceを記録すると、React専用のトラックが追加されます。Schedulerトラックは、Blocking(ユーザー操作などの同期更新)、Transition(startTransition の更新)、Suspense、Idleの4つのサブトラックに分かれます。どの優先度の作業がいつ描画されたかが見えます。Componentsトラックには、コンポーネントの描画とEffectの実行時間がフレームグラフで出ます。
表示されるのは開発ビルドとプロファイリングビルドだけで、本番ビルドでは計測のオーバーヘッドを避けるため無効です。本番相当で測るには、バンドラの設定で react-dom/client を react-dom/profiling に差し替えます。プロファイリングビルドの既定はSchedulerトラックだけです。Componentsトラックには <Profiler> で包んだ範囲だけが出ます(React Developer Toolsの拡張を入れていれば全コンポーネントが出ます)。
Partial Pre-renderingの手順:prerenderによる静的HTML生成とresumeによる描画再開
Partial Pre-renderingは、ページの静的な部分を先にHTMLとして作ってCDNから配り、動的な部分だけを後からサーバーで描画する仕組みです。19.2で、prerender が中断時の状態(postponed)を返すようになり、それを受け取って続きを描画する resume 系のAPIが加わりました。
import { prerender } from 'react-dom/static';
import { resume } from 'react-dom/server';
// ビルド時:AbortControllerで途中で止める
const controller = new AbortController();
const pending = prerender(<App />, { signal: controller.signal });
setTimeout(() => controller.abort(), 0);
const { prelude, postponed } = await pending;
await savePostponedState(JSON.stringify(postponed));
// prelude(静的HTML)をCDNへ
// リクエスト時:保存した状態から続きを描画
const state = JSON.parse(await getPostponedState(request));
const stream = await resume(<App />, state);
19.2.8で、<Suspense> の中に未解決のデータを読むコンポーネントを置いて試しました。結果は次のとおりです。
preludeはUTF-8で234バイト(文字列長は212)で、見出しと<Suspense>のfallback(「読み込み中…」)だけを含んでいました。postponedはJSONに変換でき(624バイト)、resumeに渡して描画できました。resumeの出力は、隠し要素に入った動的部分とfallbackを置き換えるscriptだけです。見出しなどpreludeの部分は含まれません。- 中断せずに最後まで描画できた場合、
postponedはnullです。
resume の出力は、prelude を送った後に同じレスポンスへ続けて流す前提の断片です。単独で返してもページになりません。API名はWeb Streams用とNode Streams用で分かれています(resume/resumeToPipeableStream、resumeAndPrerender/resumeAndPrerenderToNodeStream)。Node.jsでは、公式は性能と圧縮対応の観点からNode Streams版を推奨しています。実際のHTTP圧縮は、サーバーやミドルウェアの設定も確認します。SSR・SSG・ISRの違いそのものはSSR・CSR・SSG・ISG・ISRの違いと使い分けで比較しています。
SSRとツールまわりの変更:Suspenseのバッチ表示・useId・ESLint
ストリーミングSSRでのSuspenseのバッチ表示
19.1までは、サーバーから届いたSuspenseの中身はすぐにfallbackと入れ替わっていました。19.2からは、少しの間待って複数の境界をまとめて表示します。クライアント描画と動きを揃えるための修正です。ページ読み込みが2.5秒(LCPの「良好」の基準)に近づくと、Reactはまとめるのをやめてすぐ表示します。上のPartial Pre-renderingの prelude の末尾に入っていた requestAnimationFrame のscriptは、この待ち時間の計測に使われます。
useIdの形式が _r_0_ に変わった影響
useId が返すIDを実際に出力すると、19.1.9は «r0»、19.2.8と19.3.0は _r_0_ でした。view-transition-name とXML 1.0の名前で使える形式にするための変更です。useId の値をスナップショットテストやE2Eテストのセレクタに直接書いている場合は、19.2に上げると一致しなくなります。テストでは getByRole やラベルで要素を取る書き方に置き換えます。
eslint-plugin-react-hooksの版別設定:6.xと7.xの推奨プリセット
19.2と同日の2025年10月1日に出た eslint-plugin-react-hooks 6.1.0で、recommended がflat config向けになりました。6.1.0には設定形式の不具合があり、6.1.1(2025年10月3日)で直っています。6.xで旧形式(.eslintrc)を使い続ける場合は plugin:react-hooks/recommended-legacy に書き換え、React Compiler関連ルールは任意で有効にします。7.0.0(2025年10月8日)以降は recommended-legacy が無くなり、推奨設定にCompiler関連ルールも含まれます。flat configは configs.flat.recommended、旧形式は plugin:react-hooks/recommended を使います。Compilerを使うかどうかの判断はReact Compilerとは?自動メモ化の仕組みと導入方法で扱っています。
19.2.1〜19.2.8の修正内容:RSCの脆弱性対策・不具合修正・性能改善
| 版 | npm公開日 | 内容 |
|---|---|---|
| 19.2.1 | 2025-12-03 | CVE-2025-55182(RCE)の修正 |
| 19.2.2 | 2025-12-11 | CVE-2025-55184(DoS)・CVE-2025-55183(ソース露出) |
| 19.2.3 | 2025-12-11 | CVE-2025-67779(DoS・後に不完全と判明) |
| 19.2.4 | 2026-01-26 | DoS修正の完全版(CVE-2026-23864) |
| 19.2.5 | 2026-04-08 | 循環参照の保護を追加 |
| 19.2.6 | 2026-05-06 | 型の強化と性能改善 |
| 19.2.7 | 2026-06-01 | 19.2.6のFormData欠落を修正 |
| 19.2.8 | 2026-07-21 | デコード時の性能改善 |
8本ともGitHubのリリースノートは「React Server Components」の項目だけで、Activity や useEffectEvent の修正は1つもありません。脆弱性の対象は react-server-dom-webpack・react-server-dom-parcel・react-server-dom-turbopack で、サーバーを使わないReactアプリは影響を受けません。React公式は、19.2.3までのパッチではDoS対策が不完全だったとして再更新を求めました。RSCを使う構成の下限は19.2.4です。19.2.6でServer ActionsのFormDataが欠ける不具合が入り、19.2.7で直っているため、19.2系に留まるなら19.2.8まで上げます。脆弱性の経緯と影響範囲はReact Server Componentsの脆弱性CVE-2025-55182とはにまとめています。
19.2から19.3へ上げる判断:19.2系には戻されない修正
19.3.0(2026年9月9日)には、19.2で入った機能の不具合修正がまとまって入っています。どれも19.2系のパッチには入っていません。
forwardRef・memoの中のuseEffectEventが最新の値を読むように修正- 隠した
<Activity>の中のポータルの中身も隠すように変更 - 隠している間に起きたストアの変更を
useSyncExternalStoreが取りこぼす不具合の修正 - 隠した
<Activity>内のエラーが表示中のUIへ伝わらないように修正 hiddenに切り替えた後も<title>が<head>に残る不具合の修正
<Activity> か useEffectEvent を本番で使っているなら、19.3へ上げるべきです。19.2系のまま回避策を重ねるより安全です。どちらも使っておらず、RSCのパッチだけを追いたい場合は、利用中のフレームワークの対応版と既知の不具合を確認したうえで、19.2.8に留まる判断もできます。19.3では <ViewTransition> とFragment refsが安定版になり、互いに無関係なTransitionが別々に描画されるようになりました。このため、Transitionの完了順に依存した処理は上げた後に確認が要ります。19.3で増えたAPIの動くコードと、更新時に挙動が変わる箇所の一覧はReact 19.3の新機能|ViewTransition・Fragment ref・browser()の実装と19.2からの更新手順にまとめています。19.3の非同期まわりの書き方はAsync Reactとは?Transition・Suspense・useOptimisticで非同期UIを組む実装【React 19.3】で、19.3の機能全体は冒頭のReact 19の解説記事で扱っています。
よくある質問
React 19.2に破壊的変更はありますか?
公開APIの削除はありません。影響が出やすいのは、useId の出力が «r0» から _r_0_ に変わった点と、eslint-plugin-react-hooks の recommended がflat config向けになった点です。前者はIDを文字列で照合するテストが、後者は .eslintrc の設定が対象です。
React 19.1と19.2の違いは何ですか?
19.2で <Activity>・useEffectEvent・cacheSignal・Performance Tracks・Partial Pre-renderingの resume 系APIが加わりました。19.1.9にはこれらがexportされておらず、useEffectEvent を呼ぶとTypeErrorになります。19.1.0(2025年3月28日)の主な追加はOwner Stacksです。
useEffectEventでESLintの警告が出るのはなぜですか?
返り値を依存配列に入れると exhaustive-deps が警告し、Effect以外(イベントハンドラーやレンダー中)から呼ぶと rules-of-hooks がエラーにします。どちらも eslint-plugin-react-hooks 6.1.0以降が useEffectEvent を認識して出すものです。古いプラグインのままだと逆に依存配列へ追加するよう促されるため、プラグインを先に上げます。
React 19.3では何が変わりましたか?
<ViewTransition> とFragment refsが安定版になり、react-dom に browser() が、DOMの書き込みにTrusted Typesへの対応が入りました。19.2の useEffectEvent と <Activity> の不具合修正も19.3に含まれます。
React 20はいつ出ますか?
2026年10月3日時点で、npmの react に20.0.0は公開されていません。React公式も公開日を発表していません。latest タグは19.3.0、canary タグは19.3.0系の開発版を指しています。
関連記事
- React 19とは?18からの変更点・新機能とReact Compiler・最新バージョンを解説
- Async Reactとは?Transition・Suspense・useOptimisticで非同期UIを組む実装【React 19.3】
- React Hooksの使い方|useState・useEffectの基本とReact 19.2の新フック
- React Server Components(RSC)とは?サーバー・クライアントの違いと使い分けを実装例で解説
- React Server Componentsの脆弱性CVE-2025-55182とは|仕組み・影響範囲・後続CVEの時系列【2026年10月】