React 19.2: Activity APIの習得とINP革命
2026年4月までに、ReactエコシステムはHooksの導入以来、最も重要な変革を遂げました。React v19.2.4の安定版リリースにより、フレームワークは単なるコンポーネントのレンダリングを超え、インテリジェントなライフサイクル管理の領域へと進化しました。React Compiler(React Forget)が自動メモ化を一般化させる一方で、シニアエンジニアたちは今、より強力なプリミティブであるActivity APIに注目しています。
本ガイドでは、React 19.2がコンポーネントの「アクティビティ(活動状態)」をどのように管理するのか、なぜ実験的な「Offscreen」という名称から安定版の「Activity」APIへの移行が重要なのか、そしてこれらのツールを使用して複雑なアプリケーションで完璧に近いInteraction to Next Paint (INP) スコアを達成する方法について深く掘り下げます。
2026年の展望:React 19.2が新しい標準に
2024年が「Actions」の年、2025年が「Compiler」が主流になった年だとすれば、2026年は**リソース効率(Resource Efficiency)**の年です。私たちはもはや単に速くレンダリングすることを目指すのではなく、「賢く」レンダリングすることを目指しています。
React 19.2.4は、以下のような安定した基盤を提供します。
- React Compilerがデフォルトとなり、95%のコードベースにおいて
useMemoやuseCallbackはレガシーな概念となりました。 - **Server Components (RSC)**が、バンドルサイズへの影響ゼロでデータフェッチを処理します。
- Activity APIにより、状態を失うことなくサブツリー全体を「一時停止」できるようになりました。
OffscreenからActivityへ:何が変わったのか?
長年、コミュニティは<Offscreen />と呼ばれるコンポーネントの開発を追ってきました。React 19.2において、これは**<Activity />** APIとして完成し、リリースされました。これは単なる名称変更ではなく、メンタルモデルの転換を意味しています。
「Offscreen(画面外)」は、単に見えていないという視覚的な制約を暗示します。しかし、「Activity(活動)」はライフサイクルの制約を暗示します。**Active(アクティブ)**なコンポーネントとは、現在ユーザーの即時のインタラクションループに参加しているものです。一方、**Hidden(非表示)**なコンポーネントとは、存在し、内部状態(スクロール位置やフォーム入力など)を維持しながらも、Reactのスケジューラによって優先順位を下げられたものを指します。
従来の切り替え手法の問題点
React 19.2以前、非表示のUI(バックグラウンドのタブなど)を処理するには、2つの不完全な方法しかありませんでした。
- 条件付きレンダリング (
{show && <Component />}): コンポーネントが破棄されます。ユーザーが元のタブに戻ったとき、スクロール位置や入力途中のフォームデータ、ローカル状態はすべて失われます。再マウントの際に「ローディングのちらつき」が発生します。 - CSSによる非表示 (
display: none): 状態は保持されますが、パフォーマンス面では悪夢です。Reactの目にはコンポーネントツリーは「アクティブ」なまま映ります。バックグラウンドのタブが重い再レンダリングやuseEffectのタイマーをトリガーすると、表示されているUIとCPUリソースを奪い合い、**Interaction to Next Paint (INP)**を低下させます。
ディープダイブ:Activity APIの仕組み
<Activity />コンポーネントは、この「一時停止」状態を宣言的に管理する方法を提供します。
import { Activity, useState } from 'react';
function Dashboard() {
const [activeTab, setActiveTab] = useState('overview');
return (
<main>
<Tabs onChange={setActiveTab} />
{/* Overviewは選択されているとき常に表示される */}
<Activity mode={activeTab === 'overview' ? 'visible' : 'hidden'}>
<OverviewTab />
</Activity>
{/* Analyticsは重いため、メモリには保持するが 'hidden' にしておく */}
<Activity mode={activeTab === 'analytics' ? 'visible' : 'hidden'}>
<AnalyticsTab />
</Activity>
</main>
);
}
1. 状態の保持 (State Preservation)
mode="hidden"の場合、DOM要素は保持されますが(hidden属性が適用されます)、より重要なのはFiberツリーがそのまま維持されることです。ユーザーが<AnalyticsTab />内の入力欄に「Hello World」と入力した後にOverviewに切り替えても、戻ってきたときにはそのテキストはそのまま残っています。
2. エフェクトのライフサイクル管理
これがReact 19.2の「キラー機能」です。Activityがhiddenに移行すると:
- Reactはそのサブツリー内にあるすべての
useEffectフックのクリーンアップ関数を自動的に実行します。 - 再び
visibleになると、エフェクトは再同期(再実行)されます。
これにより、ユーザーが見ていない間にバックグラウンドのコンポーネントがAPIをポーリングしたりアニメーションループを実行したりすることがなくなり、バッテリーとCPUを節約できます。
3. useEffectEventの威力
この移行をスムーズに処理するために、React 19.2のデベロッパーはuseEffectEventフックを使用します。これにより、不要な再レンダリングをトリガーすることなく、Activityの状態変化に反応すべきロジックを定義できます。
function ChatRoom() {
const onConnect = useEffectEvent(() => {
console.log("チャット接続を再同期中...");
socket.connect();
});
useEffect(() => {
onConnect();
return () => socket.disconnect();
}, []); // Activityモードが変化したときに自動的に再同期される
return <div className="chat">...</div>;
}
INP革命:2026年にパフォーマンスが重要な理由
Googleの**Interaction to Next Paint (INP)**は2024年にCore Web Vitalsの指標となりましたが、2026年においてはSEOとユーザー継続率の主要な指標となっています。Activity APIは、INPに対する究極の武器です。
Reactのスケジューラが<Activity mode="hidden">を検知すると、そのサブツリー全体を**低優先度 (Low Priority)**としてマークします。その非表示のツリー内でトリガーされた更新(例:バックグラウンドのWebSocketによる更新)は、表示されているツリー内でのユーザーのクリックやスクロールを妨げることは決してありません。
ベンチマークによる違い
1タブあたり50以上のコンポーネントを持つ複雑なダッシュボードの場合:
- Activityなし: タブの切り替えにより、マウント/アンマウントのオーバーヘッドで250ms以上のINPスパイクが発生。
- Activityあり: DOMが既に存在し、Reactは
visible状態の切り替えとエフェクトの再同期を行うだけで済むため、切り替えはほぼ瞬時(16ms未満)。
比較表:モダンなUI切り替え戦略
| 機能 | 条件付きレンダリング | CSS display: none | Activity API (19.2) |
|---|---|---|---|
| 状態の保持 | なし(リセット) | あり | あり |
| DOMの永続性 | なし | あり | あり |
| エフェクトの動作 | クリーンアップされる | バックグラウンドで動作 | 一時停止/クリーンアップされる |
| レンダリング優先度 | 高(ブロッキング) | 高(ブロッキング) | 低(遅延実行) |
| 理想的なユースケース | モーダル、単純な切り替え | 小規模で静的なUI | 複雑なタブ、プリレンダリング |
React 19.2 Activityのベストプラクティス
この新しいAPIを最大限に活用するために、2026年の以下のパターンに従ってください。
「プリレンダリングの肥大化」を避ける
10個のタブをメモリに保持できるからといって、そうすべきだとは限りません。非表示のActivityはそれぞれメモリを消費します。「最近使ったもの(LRU)」キャッシュパターンを使用して、最も関連性の高い3〜4個のタブのみをActivityブロックに保持し、残りは条件付きレンダリングを使用してください。
Server Actionsとのシナジー
React 19.2のActionsはActivityと完璧に連携します。バックグラウンドのタブがuseOptimisticを介して「楽観的更新」を行っている場合、Activity APIはその更新のバックグラウンドレンダリングが現在のフォアグラウンドタスクのカクつきを引き起こさないように保証します。
Activityの遷移を監視する
新しく導入されたuseActivityStatus()フック(19.2.2で導入)を使用して、コンポーネントがバックグラウンドに移動したことを検知します。これは、下書きデータの保存や、高負荷なWebGLキャンバスの一時停止に役立ちます。
function VideoPlayer() {
const status = useActivityStatus(); // 'visible' | 'hidden'
useEffect(() => {
if (status === 'hidden') {
videoRef.current.pause();
}
}, [status]);
return <video ref={videoRef} ... />;
}
FAQ:React 19.2に関するよくある質問
<Activity /> は <Suspense /> の代わりになりますか?
いいえ。<Suspense /> はコンポーネントのローディング状態を処理します。<Activity /> は既にロードされたコンポーネントの表示状態と優先順位を処理します。これらは併用されることが多く、Activityの中にデータフェッチのためのSuspense境界が含まれることもあります。
React CompilerはActivityを自動的に処理しますか?
Compilerはコンポーネントが最適化されることを保証しますが、コンポーネントをいつ非表示にすべきかは判断しません。UIのどの部分が現在ユーザーのフォーカス外であるかをReactに伝えるには、依然として<Activity />コンポーネントを使用する必要があります。
2026年におけるReact 19.2のブラウザサポートは?
2026年までに、すべての主要なモダンブラウザ(Chrome 120+、Safari 18+、Firefox 125+)は、CSSの content-visibility: hidden や最新のスケジューリングAPIなど、Activity APIに必要な基盤となるプリミティブを完全にサポートしています。
結論
React 19.2は、フレームワークが単なる「ビューライブラリ」ではなく、洗練された**UIオーケストレーター(UI Orchestrator)**へと進化した転換点となります。Activity APIをマスターすることで、機能豊富でありながら驚異的なパフォーマンスを誇るアプリケーションを構築できます。
2026年において、優れた開発者と卓越した開発者の違いは、ユーザーに「見せていない」リソースをいかに管理するかにあります。今日から複雑なインターフェースに <Activity /> を取り入れ、モダンなウェブ時代にユーザーが期待する瞬時の体験を提供しましょう。
UnterGletscher Tech Blog — 2026年のウェブ開発の最前線から、最も鋭い洞察をお届けします。