開発

React 19.3の新機能|ViewTransition・Fragment ref・browser()の実装と19.2からの更新手順

React 19.3の新機能|ViewTransition・Fragment ref・browser()の実装と19.2からの更新手順

React 19.3は2026年9月9日に公開され、10月11日時点でnpmのlatestタグは19.3.0を指しています。目玉は、2025年に実験的APIとして紹介された<ViewTransition>とFragment refが安定版になったことです。ほかにSSRでブラウザ専用の描画をクライアントへ回すbrowser()、Trusted Types対応、Server ComponentsからのContext直接描画が加わりました。この記事ではReact公式ブログの19.3告知を正として、動かせるコード、19.2から上げるときに挙動が変わる箇所、新機能を入れない画面の条件をまとめました。19.2で入った<Activity>やuseEffectEventはReact 19.2の新機能|Activity・useEffectEvent・cacheSignal・PPRの使い方で扱っています。

まとめ:React 19.3で安定版になった機能と19.2から上げる前の確認4点

  • 19.3.0は2026年9月9日公開。10月11日時点でパッチ版(19.3.1)は出ていません。
  • <ViewTransition>とFragment refが安定版になり、addTransitionType、browser()、Trusted Types対応、Server ComponentsでのContext直接描画が加わりました。
  • 公式ブログに破壊的変更の記載はありません。ただしTransitionの並列描画、hydration時のStrict Modeの二重実行など、動きが変わる変更は入っています。
  • <ViewTransition>はDOM専用です。React Nativeの画面には使えません。

React 19.3のリリース日と追加機能の一覧・npmで入っている版を確かめる手順

2026年9月9日公開の19.3.0とnpmのlatestタグで確かめる版番号

npm registryの公開日時を見ると、reactとreact-domの19.3.0はどちらも2026年9月9日の公開です。直前の19.2系は19.2.8(2026年7月21日)が最後で、型定義の@types/reactも同じ日に19.3.0が出ています。手元のプロジェクトでどの版が解決されているかは、次のコマンドで確かめられます。

npm view react version
npm ls react react-dom
npm view react time --json

1行目はレジストリの最新版、2行目はプロジェクトに実際に入っている版です。reactとreact-domの版がずれていると、react-dom 19.3.0はreactの^19.3.0を要求するため依存解決で警告が出ます。公式の版一覧はReact Versionsにもまとまっています。

安定版になった2つの機能と新規APIの収録パッケージを比べる対応表

19.3の追加分を、どのパッケージに入ったかと合わせて整理すると次のとおりです。

機能 パッケージ 19.3での扱い
<ViewTransition> react 実験版から安定版へ
addTransitionType react 遷移の向きを付ける
Fragment ref react 実験版から安定版へ
browser() react-dom 新規API
Trusted Types対応 react-dom 値を文字列化しない
Context直接描画 react-server Providerの部品が不要に

browser()はreactではなくreact-domから読み込む点に注意してください。

ViewTransitionで要素の出現と消滅をアニメーションさせる実装手順

startTransitionで包んだ更新だけが動くenterとexitの基本形

<ViewTransition>は、ブラウザのView Transition APIを使って、子要素の出現(enter)、消滅(exit)、内容の変化(update)、名前付き要素の移動(share)をアニメーションさせる部品です。

import { ViewTransition, useState, startTransition } from 'react';

export default function Panel() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => startTransition(() => setOpen(v => !v))}>
        {open ? '閉じる' : '開く'}
      </button>
      {open && (
        <ViewTransition>
          <section className="detail">詳細の内容</section>
        </ViewTransition>
      )}
    </>
  );
}

動くのはstartTransitionの中の更新、<Suspense>の表示切替、useDeferredValueによる更新の3種類だけです。onClickの中でsetOpenを直接呼ぶと、要素は即座に切り替わりアニメーションしません。既定の動きはクロスフェードで、入力への反応を優先する通常の更新を巻き込まない設計になっています。

addTransitionTypeで次へと前への向きを分けるカルーセル実装

同じsetStateでも、操作の理由で動きを変えたい場面があります。addTransitionTypeはTransitionに種類の名前を付け、enterやexitのpropsで種類ごとにCSSクラスを割り当てます。

import { ViewTransition, addTransitionType, startTransition } from 'react';

function next() {
  startTransition(() => {
    addTransitionType('next');
    setIndex(i => i + 1);
  });
}

<ViewTransition
  key={slide.id}
  enter={{ next: 'from-right', previous: 'from-left' }}
  exit={{ next: 'to-left', previous: 'to-right' }}
>
  <Slide slide={slide} />
</ViewTransition>

from-rightなどはCSS側で定義するクラス名です。Reactは種類の名前をブラウザのview transition typeとしても付けるため、CSSの:active-view-transition-type(next)で範囲を絞った書き方もできます。keyを変えて要素を差し替えることで、旧スライドのexitと新スライドのenterが同時に走ります。

Suspenseのfallbackから本体への切替だけを動かす設定例

データ取得と組み合わせると、読み込み表示から本来の内容へ切り替わる瞬間をアニメーションにできます。公式ブログが勧める型は「fallbackは即表示、fallbackから本体への切替だけ動かす、取得済みなら動かさない」の3原則です。

<ViewTransition update="auto" default="none">
  <Suspense fallback={<CardSkeleton />}>
    <ProfileCard userId={id} />
  </Suspense>
</ViewTransition>

default="none"でenterとexitを止め、update="auto"で切替だけを残します。この指定を省くと、キャッシュ済みで一瞬で出る場面でもフェードが入るため、操作のたびに画面がもたつく印象になるのが難点です。Suspenseとuseでデータを読む書き方そのものは、Async Reactとは?Transition・Suspense・useOptimisticで非同期UIを組む実装で詳しく扱っています。

動かないときに疑うDOM要素との配置順序とnameの重複エラー

「書いたのにアニメーションしない」の原因で最も多いのは置き場所です。リファレンスのトラブルシューティングによると、enterとexitが動くのは<ViewTransition>がDOM要素より外側にあるときだけです。<div>の内側に置くと発動しません。

もう1つは共有要素用のnameです。同じnameの<ViewTransition>が同時にマウントされるとエラーになるため、一覧の各行に使うならname={`item-${id}`}のようにIDを含めて一意にします。prefers-reduced-motionをReactは自動で無効化しないので、CSSの@media (prefers-reduced-motion)でアニメーションを止める指定は自分で書いてください。ブラウザごとのView Transitions APIの対応状況はView Transitions APIの対応ブラウザと実装手順で確認できます。

Fragment refでラッパーのdivを足さずに複数の子要素を操作する方法

FragmentInstanceが持つイベント・フォーカス・監視・計測の4系統

19.3から<Fragment>にrefを渡せるようになり、ref.currentにはFragmentInstanceが入ります。これまで複数の兄弟要素をまとめて監視するには、ref用の<div>を足すしかなく、FlexboxやGridのレイアウトが崩れる原因になっていました。

  • イベント:addEventListener、removeEventListener、dispatchEvent(第1階層の子が対象)
  • フォーカス:focus、focusLast、blur(入れ子の子を深さ優先でたどる)
  • 監視:observeUsing、unobserveUsing(IntersectionObserverやResizeObserverを接続)
  • 計測:getClientRects、getRootNode、compareDocumentPosition、scrollIntoView

外部ライブラリの部品がrefを受け取らない場合でも、Fragmentで包めば外側から振る舞いを足せます。単一要素へのrefの基本はuseRefの使い方|DOM参照・値の保持とuseStateとの違いを参照してください。

IntersectionObserverを接続して表示状態を返すInView部品の実装例

子要素のどれか1つでも画面に入ったらonChange(true)を呼ぶ部品は、次のように書けます。公式ブログの例を、実務で使いやすい形に短くしたものです。

import { Fragment, useRef, useLayoutEffect } from 'react';

export function InView({ onChange, children }) {
  const ref = useRef(null);
  useLayoutEffect(() => {
    const visible = new Set();
    const observer = new IntersectionObserver(entries => {
      entries.forEach(e => e.isIntersecting ? visible.add(e.target) : visible.delete(e.target));
      onChange(visible.size > 0);
    });
    const fragment = ref.current;
    fragment.observeUsing(observer);
    return () => fragment.unobserveUsing(observer);
  }, [onChange]);
  return <Fragment ref={ref}>{children}</Fragment>;
}

後片付けでunobserveUsingを呼ばないと、部品が消えたあとも監視が残ります。onChangeを親で毎回作り直すと購読も毎回やり直しになるため、親側でuseCallbackに包むか、React Compilerを入れている環境ならその自動メモ化に任せてください。

browser()でSSR中にブラウザ専用の描画をクライアントへ回す書き方

useEffectのmountedフラグを置き換えるuse(browser())の基本形

localStorageやブラウザのタイムゾーンに依存する部品は、サーバーで正しいHTMLを作れません。これまではuseEffectでmountedフラグを立てるか、typeof windowで分岐していました。後者はサーバーとクライアントでHTMLが食い違い、ハイドレーションエラーの典型的な原因になります。

import { Suspense, use } from 'react';
import { browser } from 'react-dom';

function TimeZone() {
  use(browser());
  const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
  return <p>{tz}</p>;
}

export default function App() {
  return (
    <Suspense fallback={<p>読み込み中…</p>}>
      <TimeZone />
    </Suspense>
  );
}

サーバーではuse(browser())がSuspenseを起こし、最寄りの境界のfallbackがHTMLに入ります。ブラウザではsuspendせずにそのまま描画が進みます。通常のuseと同じく、条件分岐や早期returnの後でも呼べるので、「初期値が渡されていればサーバーで描き、無ければブラウザへ回す」という書き分けも可能です。useそのものの規則はReactのuseフック(use API)の使い方にまとめています。

Suspense境界が無いと失敗する制約とonBrowserBailoutでの記録

browserのリファレンスには、注意点が3つ書かれています。サーバー描画中は<Suspense>の内側で呼ぶこと(無いとサーバー描画が失敗する)、Client Componentから呼ぶこと、browser()を単独で呼んでも何も起きずuseに渡す必要があること、の3点です。

どの部品がクライアントへ回されたかは、サーバー描画APIのonBrowserBailoutで記録できます。browser()の引数に理由を渡すと、記録されるエラーのcauseに入ります。

const { pipe, abort } = renderToPipeableStream(<App />, {
  onShellReady() {
    pipe(res);
    setTimeout(() => abort(browser('server render timed out')), 10000);
  },
  onBrowserBailout(error, errorInfo) {
    console.warn(error.cause, errorInfo.componentStack);
  },
});

abortにbrowser()の戻り値を渡すと、10秒で間に合わなかったSuspense境界をfallbackのまま送り、残りをブラウザで描かせられます。この経路ではonErrorもhydrateRootのonRecoverableErrorも呼ばれないため、監視をonErrorだけに頼っていると、クライアント描画へ落ちた件数が見えなくなります。

Trusted Types対応とサーバー側のContext直接描画の実装変更

CSP設定時にinnerHTMLへの型付きオブジェクト代入が通る理由

Trusted Typesは、DOMベースのXSSを防ぐブラウザの仕組みです。CSPのrequire-trusted-types-forで有効にすると、innerHTMLなどへ生の文字列を入れることが禁止され、ポリシーを通して作ったTrustedHTMLなどの型付きオブジェクトだけが受け付けられます。仕様はW3CのTrusted Types仕様にあります。

Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app-html

const policy = trustedTypes.createPolicy('app-html', {
  createHTML: input => DOMPurify.sanitize(input),
});
<div dangerouslySetInnerHTML={{ __html: policy.createHTML(html) }} />

19.2までのReactは値を'' + valueで文字列に戻していたため、せっかく作ったTrustedHTMLがただの文字列になり、ブラウザに拒否されていました。19.3は値を文字列化せずに渡すので、ポリシーが意図どおり効きます。XSS対策全体の考え方はXSSとCSRFの違い|仕組み・対策を実装レベルで比較で整理しています。

Server ComponentからのContext直接描画で省ける部品

Server ComponentはContextを作れませんが、19.3からは'use client'のファイルで作ったContextを読み込んで、そのまま描画できます。これまではContextを渡すためだけのUserProvider部品を別に書いていました。

// user-context.js
'use client';
import { createContext } from 'react';
export const UserContext = createContext(null);

// layout.js(Server Component)
import { UserContext } from './user-context';
export async function Layout({ children }) {
  const currentUser = await getCurrentUser();
  return <UserContext value={currentUser}>{children}</UserContext>;
}

ログイン利用者などをクライアント側へ配るためだけのContextで、部品が1つ減ります。Contextの基本はReact Contextの使い方、サーバーとクライアントの境界の考え方はReact Server Components(RSC)とは?を参照してください。

19.2から19.3へ上げるときに挙動が変わる変更点と更新コマンド

npm installで上げるパッケージと@types/reactの版合わせ

reactとreact-domは必ず同時に上げます。TypeScriptの環境では@types/reactと@types/react-domも19.3系へそろえないと、<ViewTransition>やbrowserの型が見つからずエラーになります。

npm install react react-dom
npm install -D @types/react @types/react-dom
npm ls react react-dom @types/react

最後の行で、すべてが19.3.0に解決されたことを確かめてください。package.jsonの範囲指定が~19.2.0のように固定されている場合は、範囲を書き換えてからパッケージを入れ直してください。Next.jsなどのフレームワーク経由で使っている場合は、フレームワーク側でどの版に対応しているか、対応版の告知も合わせて確認する必要があります。Next.jsの直近の変更はNext.js 16.3とは?にまとめています。

Transitionの並列描画とSSR時のStrict Mode二重実行の影響

Changelogのうち、既存アプリの動きを変えうるのは次の2つです。

1つ目はTransitionの並列描画(PR #37290)です。これまで同時に進む複数のTransitionは1回の描画にまとめられていましたが、19.3では個別に描画されます。遅い画面遷移があっても、無関係な検索欄の絞り込みは、その画面遷移の完了を待つ必要がありません。その代わり、2つのTransitionの結果が同じ瞬間に画面へ出ることを前提にした実装は、間の状態が一瞬見える可能性があります。

2つ目はhydration時のStrict Modeの二重実行(PR #35961)です。SSRしたページでも、開発環境ではEffectが2回走るようになりました。クライアント描画のルートと同じ動きにそろえる変更で、本番の挙動は変わりません。ただし開発中に「SSRのページだけEffectが1回」を前提にしていたログ送信や計測コードは、19.3で重複して見えます。

number入力のdefaultValueなど細かな挙動変更の確認先

小さな変更では、type="number"の入力欄のdefaultValueの更新が他の入力型と同じ扱いになりました。フォームを再描画したときに初期値が書き換わるかどうかが変わるので、数値入力を多く持つ業務画面では一度動かして確かめてください。

ほかに、Server Actionによるフォームの自動リセットでonResetが発火する変更や、useDeferredValueが古い値のまま止まる不具合の修正が入りました。全件は公式ブログ末尾のChangelogで確認できます。

React 19.3の新機能を本番に採用する条件と見送る画面の判断基準

ViewTransitionを入れてよい画面と入れない画面の条件

ViewTransitionを入れてよいのは、一覧から詳細への遷移、タブやカルーセルの切替、Suspenseで遅れて出るカードなど、「どこからどこへ移ったか」を示すと操作が分かりやすくなる画面です。逆に、次の画面には入れないでください。

  • 入力の手数が多い業務画面(受注入力、伝票登録など)。1回ごとの演出は短くても、1日に数百回繰り返す操作では待ち時間として積み上がる
  • React Nativeと部品を共有している画面。DOM専用のため、ネイティブ側で同じ表示にならない
  • ルーターが従来のpopstateで戻る操作を処理している画面。リファレンスによると、Reactはこの場合のアニメーションを飛ばすため、戻る操作だけ動かない不揃いな画面になる

判断の軸は「動きが情報を運ぶか」です。装飾だけのアニメーションなら入れません。

19.2系に留まる場合に失う修正と不具合対応で更新を急ぐべき構成

19.2系の最新は7月21日の19.2.8で、10月11日時点でそれ以降のパッチは出ていません。19.3に破壊的変更は無いため、更新の手間は小さい部類です。特に、CSPでTrusted Typesを強制したいサイト、useDeferredValueや<Activity>の不具合に当たっているアプリは、19.3の修正を取り込むのが現実的な解決手段になります。

一方、新APIを急いで入れる必要はありません。まず版だけを上げて既存の画面が変わらないことを確かめ、ViewTransitionやbrowser()は画面の改修のついでに部分ごとに入れる、という2段階が安全です。React 19全体の変更点はReact 19とは?18からの変更点・新機能で通して確認できます。版の更新と画面改修を同時に進める余力が社内に無い場合は、業務用・Webアプリ開発で、既存Reactアプリの更新計画から改修までを請け負っています。

React 19.3の新機能と既存アプリの更新についてのよくある質問

React 19.3の公開時期、互換性、新APIの使いどころについて、検索の多い質問に答えます。

React 19.3はいつリリースされましたか?最新版はいくつですか?

2026年9月9日に19.3.0が公開されました。npm registryの記録では、10月11日時点でreactとreact-domのlatestタグは19.3.0のままで、パッチ版は出ていません。npm view react versionで現在の最新版を確かめられます。

React 19.3に破壊的変更はありますか?

公式ブログに破壊的変更や非推奨の記載はありません。ただしTransitionの並列描画など、既存の動きが変わる項目はあるため、版を上げたら遷移の多い画面とSSRのページを一通り動かしてください。

ViewTransitionはReact Nativeでも使えますか?

使えません。React 19.3の<ViewTransition>はDOMでのみ動き、公式リファレンスはReact Nativeなど他の環境への対応を作業中としています。WebとReact Nativeで部品を共有している場合は、Web側だけで包むか、ネイティブ側は別のアニメーション手段で組む必要があります。

ViewTransitionは未対応のブラウザでどう動きますか?

未対応ブラウザでの挙動はReactのリファレンスに明記が無いため、対象ブラウザの実機で確かめるのが確実です。19.3ではMobile Safariで<ViewTransition>が落ちる不具合が直っており、19.3より前のCanary版で試していた場合は版を上げてから確認してください。

browser()とuseEffectのmountedフラグはどちらを使うべきですか?

19.3以降でSSRを使っているならuse(browser())を勧めます。mountedフラグは初回描画で一度空の表示を出し、その後に中身を差し替える仕組みなので、利用者に見える表示は2段階です。browser()はSuspenseのfallbackとして扱われるので、読み込み表示の出し方を他の非同期処理とそろえられます。ただしSuspense境界の内側で呼ぶことが条件です。

関連記事

お気に入りに入れた記事の一覧

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.09 テックブログ IDCFクラウド(IDCフロンティア)不正アクセス・ランサムウェア:影響先・復旧・データは戻るか
  2. 2026.10.09 テックブログ ニッスイのサイバー攻撃で日水物流の入出荷停止|委託先クラウド障害に荷主が備える手順
  3. 2026.10.09 テックブログ 京王電鉄のランサムウェア被害とグループ共通基盤:決済・ポイント・予約が止まった範囲と遮断の初動
  4. 2026.10.09 テックブログ スタディサプリの不正アクセスとメールアドレス3,687件|アカウント列挙を防ぐ実装
  5. 2026.01.14 テックブログ CGLA(シーグラ)とは?Lenzo(レンゾ)の半導体技術と上場・株の最新情報【2026年版】

RELATED POSTS 関連記事

目次