---
title: "React 19.2の新機能｜Activity・useEffectEvent・cacheSignal・PPRの使い方と19.2.8までの修正"
url: "https://www.issoh.co.jp/tech/details/9427/"
published: 2025-10-22
updated: 2026-10-12
categories: ["React"]
publisher: "株式会社一創"
---

# React 19.2の新機能｜Activity・useEffectEvent・cacheSignal・PPRの使い方と19.2.8までの修正

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からの変更点・新機能と最新バージョンの解説](/tech/details/4509/)で扱っています。この記事は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以上が必要です。

## <Activity>の使い方：hidden時のEffect停止とstate保持

条件付きレンダリング（`{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](https://github.com/facebook/react/issues/34818)、修正は[PR #34831](https://github.com/facebook/react/pull/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）の解説](/tech/details/4003/)を参照してください。

## 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の違いと使い分け](/tech/details/2335/)で比較しています。

## 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とは？自動メモ化の仕組みと導入方法](/tech/details/9415/)で扱っています。

## 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とは](/tech/details/10258/)にまとめています。

## 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からの更新手順](https://www.issoh.co.jp/tech/details/18249/)にまとめています。19.3の非同期まわりの書き方は[Async Reactとは？Transition・Suspense・useOptimisticで非同期UIを組む実装【React 19.3】](/tech/details/11005/)で、19.3の機能全体は冒頭の[React 19の解説記事](/tech/details/4509/)で扱っています。

## よくある質問

### 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・最新バージョンを解説](/tech/details/4509/)
- [Async Reactとは？Transition・Suspense・useOptimisticで非同期UIを組む実装【React 19.3】](/tech/details/11005/)
- [React Hooksの使い方｜useState・useEffectの基本とReact 19.2の新フック](/tech/details/3671/)
- [React Server Components（RSC）とは？サーバー・クライアントの違いと使い分けを実装例で解説](/tech/details/4003/)
- [React Server Componentsの脆弱性CVE-2025-55182とは｜仕組み・影響範囲・後続CVEの時系列【2026年10月】](/tech/details/10258/)

---

出典: [React 19.2の新機能｜Activity・useEffectEvent・cacheSignal・PPRの使い方と19.2.8までの修正](<https://www.issoh.co.jp/tech/details/9427/>)（株式会社一創）
