React 19.2
2025年10月1日 by The React Team
React 19.2がnpmで利用可能になりました!これは昨年の3回目のリリースで、12月のReact 19と6月のReact 19.1に続くものです。この投稿では、React 19.2の新機能の概要を説明し、注目すべき変更点をハイライトします。
新しいReact機能
<Activity />
<Activity>を使用すると、アプリを制御および優先順位付けできる「アクティビティ」に分割できます。Activityは、アプリの一部を条件付きでレンダリングする代替手段として使用できます:
{ isVisible && <Page /> }
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<Page />
</Activity>
React 19.2では、Activityは2つのモードをサポートします:
- hidden: 子要素を非表示にし、エフェクトをアンマウントし、Reactが作業を完了するまですべての更新を延期します。
- visible: 子要素を表示し、エフェクトをマウントし、更新を通常通り処理できるようにします。
これにより、画面に表示されているものの性能に影響を与えることなく、アプリの隠れた部分を事前レンダリングし続けることができます。
Activityを使用して、ユーザーが次にナビゲートする可能性が高いアプリの隠れた部分をレンダリングしたり、ユーザーがナビゲートした部分の状態を保存したりできます。これにより、バックグラウンドでデータ、CSS、画像を読み込むことでナビゲーションが高速化され、戻るナビゲーションで入力フィールドなどの状態を維持できます。
将来的には、さまざまなユースケースに対応するため、Activityにより多くのモードを追加する予定です。
Activityの使用例については、[Activity docs](Activity docs)をご確認ください。
useEffectEvent
useEffectの一般的なパターンの1つは、外部システムからの何らかの「イベント」についてアプリコードに通知することです。例えば、チャットルームが接続されたときに通知を表示したい場合:
function ChatRoom({ roomId, theme }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
showNotification('Connected!', theme);
});
connection.connect();
return () => { connection.disconnect() };
}, [roomId, theme]);
上記のコードの問題は、このような「イベント」内で使用される値の変更により、周囲のEffectが再実行されることです。例えば、テーマを変更するとチャットルームが再接続されます。これはroomIdのようなEffect ロジック自体に関連する値には意味がありますが、themeには意味がありません。
これを解決するため、ほとんどのユーザーはlintルールを無効にして依存関係を除外します。しかし、後でEffectを更新する必要がある場合、リンターが依存関係を最新に保つのを手助けできなくなるため、バグにつながる可能性があります。
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]);
DOMイベントと同様に、Effect Eventsは常に最新のpropsとstateを「見る」ことができます。Effect Eventsは依存関係配列で宣言すべきではありません。
リンターがそれらを依存関係として挿入しようとしないよう、eslint-plugin-react-hooks@latestにアップグレードする必要があります。
Effect Eventsは、「それらの」Effectと同じコンポーネントまたはHook内でのみ宣言できることに注意してください。これらの制限はリンターによって検証されます。
useEffectEventを使用するタイミング
useEffectEventは、ユーザーイベントではなくEffectから発火される概念的に「イベント」である関数に使用すべきです(これが「Effect Event」と呼ばれる理由です)。
すべてをuseEffectEventでラップしたり、単にlintエラーを消すために使用したりする必要はありません。これはバグにつながる可能性があります。
Event Effectsについて深く理解するには、[Separating Events from Effects](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](cacheSignal docs)をご覧ください。
Performance Tracks
React 19.2では、Reactアプリのパフォーマンスに関するより多くの情報を提供するため、Chrome DevToolsパフォーマンスプロファイルに新しいカスタムトラックセットが追加されました:
[React Performance Tracks docs](React Performance Tracks docs)では、トラックに含まれるすべてを説明していますが、ここでは高レベルの概要を示します。
Scheduler ⚛
Schedulerトラックは、ユーザーインタラクションの「blocking」やstartTransition内の更新の「transition」など、異なる優先度でReactが何を処理しているかを示します。各トラック内では、更新をスケジュールしたイベントや、その更新のレンダリングがいつ発生したかなど、実行されている作業のタイプが表示されます。
また、更新が異なる優先度を待ってブロックされているときや、Reactが継続前にペイントを待っているときなどの情報も表示されます。
Schedulerトラックは、Reactがコードを異なる優先度に分割する方法と、作業を完了した順序を理解するのに役立ちます。含まれるすべてについては、[Scheduler track docs](Scheduler track docs)をご覧ください。
Components ⚛
Componentsトラックは、Reactがレンダリングまたはエフェクト実行のために処理しているコンポーネントのツリーを示します。内部では、子要素やエフェクトがマウントされるときの「Mount」や、React外の作業に譲るためにレンダリングがブロックされるときの「Blocked」などのラベルが表示されます。
Componentsトラックは、コンポーネントがいつレンダリングされるかやエフェクトが実行されるか、およびその作業を完了するのにかかる時間を理解し、パフォーマンスの問題を特定するのに役立ちます。含まれるすべてについては、[Components track docs](Components track docs)をご覧ください。
新しいReact DOM機能
Partial Pre-rendering
19.2では、アプリの一部を事前にプリレンダリングし、後でレンダリングを再開する新しい機能を追加しています。この機能は「Partial Pre-rendering」と呼ばれ、アプリの静的部分をプリレンダリングしてCDNから提供し、後でシェルのレンダリングを再開して動的コンテンツで埋めることができます。
後で再開するためにアプリをプリレンダリングするには、まずAbortControllerを使用してprerenderを呼び出します:
const { prelude, postponed } = await prerender(<App />, {
signal: controller.signal,
});
await savePostponedState(postponed);
その後、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);
詳細については、新しいAPIのドキュメントをご覧ください:
react-dom/server
resume: Web Streams用
resumeToPipeableStream: Node Streams用
react-dom/static
resumeAndPrerender: Web Streams用
resumeAndPrerenderToNodeStream: Node Streams用
さらに、prerender APIは、resume APIに渡すpostpone状態を返すようになりました。
注目すべき変更
SSR用のSuspense Boundariesのバッチ処理
クライアントでレンダリングされるかサーバーサイドレンダリングからストリーミングされるかによって、Suspense boundariesの表示が異なる動作バグを修正しました。19.2以降、ReactはサーバーレンダリングされたSuspense boundariesの表示を短時間バッチ処理し、より多くのコンテンツを一緒に表示してクライアントレンダリングの動作と整合させます。
以前は、ストリーミングサーバーサイドレンダリング中、suspenseコンテンツは即座にフォールバックを置き換えていました。React 19.2では、suspense boundariesは短時間バッチ処理され、より多くのコンテンツを一緒に表示できます。
この修正は、SSR中のSuspenseに対する<ViewTransition>をサポートするためのアプリの準備も行います。より多くのコンテンツを一緒に表示することで、アニメーションはより大きなコンテンツバッチで実行でき、近い時間にストリーミングされるコンテンツのアニメーションチェーンを避けることができます。
注意
Reactはヒューリスティックを使用して、スロットリングがCore Web VitalsやSearch Rankingに影響しないことを保証します。例えば、総ページ読み込み時間が2.5秒(LCPで「良好」と見なされる時間)に近づいている場合、Reactはバッチ処理を停止し、スロットリングがメトリクスを逃す理由にならないよう即座にコンテンツを表示します。
SSR: Node用Web Streamsサポート
React 19.2では、Node.jsでのストリーミングSSR用Web Streamsサポートが追加されました:
renderToReadableStreamがNode.jsで利用可能になりました
prerenderがNode.jsで利用可能になりました
新しいresume APIも同様です:
resumeがNode.jsで利用可能です
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
推奨プリセットでデフォルトでflat configを使用し、新しいReact Compilerを活用したルールをオプトインで提供するeslint-plugin-react-hooks@latestも公開しました。
レガシー設定を引き続き使用するには、recommended-legacyに変更できます:
- extends: ['plugin:react-hooks/recommended']
+ extends: ['plugin:react-hooks/recommended-legacy']
コンパイラー有効ルールの完全なリストについては、[linter docs](linter docs)をご確認ください。
変更の完全なリストについては、[eslint-plugin-react-hooks changelog](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: hoistableスタイルでnonceの使用を許可 #32461
- react-dom: テキストコンテンツも持つReact所有ノードをContainerとして使用する場合の警告 #32774
注目すべきバグ修正
- react: コンテキストを"SomeContext.Provider"ではなく"SomeContext"として文字列化 #33507
- react: popstateイベントでの無限useDeferredValueループを修正 #32821
- react: useDeferredValueに初期値が渡されたときのバグを修正 #34376
- react: Client Actionsでフォーム送信時のクラッシュを修正 #33055
- react: 再suspendした場合のdehydrated suspense boundariesのコンテンツの非表示/表示 #32900
- react: Hot Reload中の広いツリーでのスタックオーバーフローを回避 #34145
- react: さまざまな場所でのコンポーネントスタックを改善 #33629, #33724, #32735, #33723
- react: React.lazy-ed Component内のReact.useのバグを修正 #33941
- react-dom: ARIA 1.3属性使用時の警告を停止 #34264
- react-dom: Suspenseフォールバック内の深くネストされたSuspenseのバグを修正 #33467
- react-dom: レンダリング中に中止後にsuspendするときのハングを回避 #34192
変更の完全なリストについては、Changelogをご覧ください。
執筆してくれたRicky Hanlonに感謝します。