OpenAIReactOct 1, 2025, 12:00 AM

React 19.2

A condensed section focused on the key takeaways first.

Original Post

Quick Digest

Summary

A condensed section focused on the key takeaways first.

openaienmodel: gpt-5-mini-2025-08-07

React 19.2

Key Points

  • Activity component for prioritized hidden rendering
  • useEffectEvent to separate event callbacks from effects
  • Partial Pre-rendering + resume APIs for SSR/SSG

Summary

React 19.2 (Oct 1, 2025) adds new primitives for prioritization and background rendering, improves SSR streaming and pre-rendering, and introduces ergonomics for effect callbacks and Server Components. It also ships new DevTools performance tracks, Web Streams support for Node, and several behavioral fixes for Suspense and rendering.

Key Points

  • Activity component
    • <Activity> lets you mark subtrees as visible or hidden. Hidden children are unmounted and their updates deferred, enabling background work (preloading data, images, CSS, and preserving state) without blocking visible UI.
  • useEffectEvent
    • Separates event callbacks from surrounding effects so callbacks always see latest props/state but are not effect dependencies. Upgrade eslint-plugin-react-hooks to the latest so the linter recognizes Effect Events.
  • cacheSignal (Server Components)
    • For React Server Components only: cacheSignal() lets cached work observe when cache() entries are no longer needed (completed, aborted, or failed) so you can cancel/cleanup work.
  • Partial Pre-rendering and new resume APIs
    • prerender returns a prelude + postponed state you can save; resume / resumeAndPrerender (and Node equivalents) let you resume streaming SSR or produce static HTML for SSG. New APIs: prerender, resume, resumeAndPrerender, plus Node-specific resumeToPipeableStream/resumeAndPrerenderToNodeStream.
  • Performance tracks in DevTools
    • New Scheduler and Components tracks expose scheduling priorities, what React is working on, blocked/paint waits, and per-component mount/effect timing to help diagnose latency.
  • SSR and streaming changes
    • Suspense reveals are batched briefly during streaming SSR to make server reveals align with client behavior and enable larger grouped animations (heuristics avoid hurting LCP). Web Streams rendering is supported in Node (renderToReadableStream/prerender/resume), but Node Streams remain recommended for performance and compression.
  • Tooling and compatibility notes
    • eslint-plugin-react-hooks@v6 published with flat config by default; legacy config available under recommended-legacy.
    • Default useId prefix changed to "r" to make generated IDs valid for view transitions and XML names.

Migration & Action Items for Engineers

  • If you use effect callbacks that should not re-run effects, adopt useEffectEvent and upgrade eslint-plugin-react-hooks.
  • Evaluate using <Activity> for background preloading and to keep UI responsive during heavy background work.
  • For Node SSR, prefer existing Node Streams APIs (renderToPipeableStream, resumeToPipeableStream, prerenderToNodeStream) for best throughput and compression support; Web Streams are available but slower in Node currently.
  • Audit any tooling or CSS that relied on the previous useId prefix and ensure compatibility with the new "r" prefix.

Where to look

  • Docs: Activity, useEffectEvent, cacheSignal, Partial Pre-rendering, Performance Tracks.
  • Changelog: full list of fixes and additional DOM/React changes.

Full Translation

Translations

A translation section that keeps the flow of the original article.

openaijamodel: gpt-5-mini-2025-08-07

React 19.2

React 19.2

公開日: 2025-10-01 作成者: The React Team

React 19.2 が npm で利用可能になりました!これは昨年に出た 3 回目のリリースで、前回は 19(12月)と 19.1(6月)です。本記事では React 19.2 の新機能の概要と注目すべき変更点を紹介します。

新しい React 機能

  • <Activity />
  • useEffectEvent
  • cacheSignal
  • Performance Tracks

<Activity />

<Activity> を使うとアプリを「アクティビティ」に分割し、制御や優先度付けができます。これはアプリの一部を条件付きレンダリングする代替として使えます。

例:

// Before
{ isVisible && <Page /> }

// After
<Activity mode={ isVisible ? 'visible' : 'hidden' }>
  <Page />
</Activity>

React 19.2 では Activity は visiblehidden の2つのモードをサポートします。

  • hidden: children を隠し、effects をアンマウントし、React にやることが残っていない間はすべての更新を延期します。
  • visible: children を表示し、effects をマウントし、更新を通常通り処理します。

これにより、画面に表示されているもののパフォーマンスに影響を与えずに、アプリの隠れた部分を事前レンダリングしてレンダリングを続けることが可能になります。ユーザーが次に移動しそうな隠れた部分を事前読み込みしたり、離れた部分の状態を保存しておくことで、データ・CSS・画像の事前読み込みや、戻るナビゲーション時の入力フィールドなどの状態保持が容易になります。

将来的には異なるユースケース向けにさらに多くのモードを追加する予定です。使用例は Activity docs を参照してください。

useEffectEvent

useEffect の一般的なパターンとして、外部システムからの「イベント」をアプリ側に通知することがあります。例えばチャットルームが接続したときに通知を表示するようなケースです。

問題: Effect の中で使う値(例: theme)が変わると Effect 全体が再実行されてしまい、意図しない再接続などが起こることがあります。多くの開発者は lint ルールを無効にして依存配列から除外しますが、それは後の変更でバグを招く可能性があります。

useEffectEvent を使うと、イベント部分のロジックを Effect 本体から切り離せます:

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]);

  // ✅ 依存関係はすべて宣言されている(Effect Events は依存関係ではない)
  // ...
}

Effect Events は DOM イベントと同様に常に最新の props と state を参照します。Effect Events は依存配列に宣言すべきではありません。linter がそれらを依存関係として挿入しようとしないよう、eslint-plugin-react-hooks@latest にアップグレードする必要があります。

注意: Effect Events はその Effect と同じコンポーネントまたは Hook 内でしか宣言できません。これらの制約は linter によって検証されます。

いつ useEffectEvent を使うか

Effect から発火される「イベント」的な関数に対して useEffectEvent を使うべきです(これが "Effect Event" と呼ばれる理由です)。ただし、lint エラーを黙らせるためだけに何でも useEffectEvent で包む必要はなく、むしろそれでバグを招くことがあります。イベントとエフェクトを分離する考え方の詳細は: Separating Events from Effects を参照してください。

cacheSignal (React Server Components 向け)

cacheSignal は React Server Components 用です。cacheSignal を使うと cache() の寿命が終わったタイミングを知ることができます:

import { cache, cacheSignal } from 'react';
const dedupedFetch = cache(fetch);

async function Component() {
  await dedupedFetch(url, { signal: cacheSignal() });
}

これにより、キャッシュ内の結果がもはや使われなくなったときに作業をクリーンアップしたり中断したりできます。例えば:

  • React がレンダリングを正常に完了したとき
  • レンダリングが中断されたとき
  • レンダリングが失敗したとき

詳細は cacheSignal docs を参照してください。

Performance Tracks

React 19.2 は Chrome DevTools のパフォーマンスプロファイルにカスタムトラックを追加し、React アプリのパフォーマンスに関する情報をより詳しく提供します。詳細は React Performance Tracks docs を参照してください。ここではハイレベルの概要を示します。

  • Scheduler ⚛

    • Scheduler トラックは、ユーザー操作に対する "blocking" や startTransition 内の更新の "transition" など、異なる優先度で React が何に取り組んでいるかを示します。
    • 各トラック内で、どのような作業が行われているか(更新をスケジュールしたイベント、レンダリングがいつ行われたかなど)が表示されます。
    • 優先度によって更新がブロックされているときや、React が続行の前にペイントを待っているときの情報も表示されます。
  • Components ⚛

    • Components トラックは、React がレンダリングや effect の実行のために処理しているコンポーネントツリーを表示します。
    • "Mount"(children のマウントや effects のマウント)や、レンダリングが React 以外の作業に譲ってブロックされているときの "Blocked" などのラベルが表示されます。
    • コンポーネントのレンダリングや effect 実行のタイミングと所要時間を理解するのに役立ちます。

新しい React DOM 機能

Partial Pre-rendering

19.2 では、アプリの一部を事前にレンダリングし、後で再開(resume)して埋める機能を追加しました。これを "Partial Pre-rendering" と呼びます。静的な部分を CDN から配信し、後からシェルを再開して動的コンテンツを埋める用途に使えます。

事前レンダリングして後で再開するには、まず AbortController とともに prerender を呼び出します:

const { prelude, postponed } = await prerender(<App />, {
  signal: controller.signal,
});

// postponed state を保存しておく
await savePostponedState(postponed);
// prelude をクライアントや CDN に送る

その後、prelude をクライアントに返し、後で resume を呼んで SSR ストリームに再開します:

const postponed = await getPostponedState(request);
const resumeStream = await resume(<App />, postponed);
// ストリームをクライアントへ送る

あるいは resumeAndPrerender を呼んで SSG 用の静的 HTML を取得できます:

const postponedState = await getPostponedState(request);
const { prelude } = await resumeAndPrerender(<App />, postponedState);
// 完成した HTML prelude を CDN に送る

詳細は各 API のドキュメントを参照してください:

  • react-dom/server: resume(Web Streams 用)、resumeToPipeableStream(Node Streams 用)
  • react-dom/static: resumeAndPrerender(Web Streams 用)、resumeAndPrerenderToNodeStream(Node Streams 用)

さらに、prerender API は resume API に渡す postponed state を返すようになりました。

注目すべき変更点

Batching Suspense Boundaries for SSR

これまで Suspense 境界はクライアントでレンダリングされた場合とサーバー側ストリーミングで出力された場合で表示のされ方が異なる振る舞いをするバグがありました。19.2 では、サーバーレンダリングの Suspense 境界の reveal(落ちていたフォールバックから実際のコンテンツへの切り替え)を短時間バッチ処理するようにして、より多くのコンテンツをまとめて公開できるようにしました。これによりクライアントレンダリング時の振る舞いと整合させます。

以前はストリーミング SSR 時にサスペンスのコンテンツがすぐにフォールバックを置き換えていましたが、19.2 では短い時間だけバッチすることで、より多くのコンテンツをまとめて reveal できるようにします。この修正は SSR 中の Suspense 向けの <ViewTransition> サポートに備えるものでもあります。

注意: React はコア Web Vitals や検索ランキングに影響しないようヒューリスティックを用いてスロットリングを制御します。例えば合計ページロード時間が 2.5 秒(LCP の「良い」目安)に近づいている場合、React はバッチ処理を中止して即座にコンテンツを公開します。

SSR: Web Streams の Node サポート

React 19.2 は Node.js でのストリーミング SSR に対する Web Streams のサポートを追加しました:

  • renderToReadableStream が Node.js で利用可能に
  • prerender が Node.js で利用可能に
  • 新しい resume API(resume / resumeAndPrerender)が Node.js で利用可能に

注意点 — Node.js では Node Streams を優先する

Node.js 環境では引き続き Node Streams API を使うことを強く推奨します:

  • renderToPipeableStream
  • resumeToPipeableStream
  • prerenderToNodeStream
  • resumeAndPrerenderToNodeStream

理由: Node 上では Node Streams の方が Web Streams より高速で、さらに Web Streams はデフォルトで圧縮をサポートしていないため、意図せずストリーミングの利点を失う可能性があります。

eslint-plugin-react-hooks v6

eslint-plugin-react-hooks@latest を公開しました。recommended preset では flat config がデフォルトになり、React Compiler 由来の新しいルールはオプトインになっています。レガシーな設定を使い続けるには recommended-legacy に変更してください。

- extends: [ 'plugin:react-hooks/recommended' ]
+ extends: [ 'plugin:react-hooks/recommended-legacy' ]

Compiler が有効にするルールの完全な一覧は linter docs を参照してください。変更の詳細は eslint-plugin-react-hooks の changelog をご確認ください。

useId のデフォルトプレフィックスを更新

19.2 では useId のデフォルトプレフィックスを :r:(19.0.0)や «r»(19.1.0)から _r_ に変更しました。もともと CSS セレクタに無効な特殊文字を使うのはユーザーが書いた ID と衝突しにくくするためでしたが、View Transitions をサポートするために useId で生成される ID を view-transition-name や XML 1.0 の名前として有効にする必要がありました。

Changelog(抜粋)

その他の注目変更

  • react-dom: Allow nonce to be used on hoistable styles #32461
  • react-dom: Warn for using a React owned node as a Container if it also has text content #32774

重要なバグ修正

  • react: Stringify context as “SomeContext” instead of “SomeContext.Provider” #33507
  • react: Fix infinite useDeferredValue loop in popstate event #32821
  • react: Fix a bug when an initial value was passed to useDeferredValue #34376
  • react: Fix a crash when submitting forms with Client Actions #33055
  • react: Hide/unhide the content of dehydrated suspense boundaries if they resuspend #32900
  • react: Avoid stack overflow on wide trees during Hot Reload #34145
  • react: Improve component stacks in various places #33629, #33724, #32735, #33723
  • react: Fix a bug with React.use inside React.lazy-ed Component #33941
  • react-dom: Stop warning when ARIA 1.3 attributes are used #34264
  • react-dom: Fix a bug with deeply nested Suspense inside Suspense fallbacks #33467
  • react-dom: Avoid hanging when suspending after aborting while rendering #34192

完全な変更一覧は Changelog を参照してください。

Thanks to Ricky Hanlon for writing this post.