12k
All articles

React 19におけるスムーズな非同期トランジション

React 19の非同期トランジションは、startTransitionとuseOptimisticで手動のローディング状態管理を不要にし、フォーム送信やデータ変更を安定させる。

OpenReplay Team
OpenReplay Team
React 19におけるスムーズな非同期トランジション

サーバーにデータを送信するフォームを構築したとします。ユーザーが「保存」をクリックしても、2秒間何も起こりません。ユーザーは再度クリックします。その結果、リクエストが重複し、UIが混乱し、ユーザーはフラストレーションを感じることになります。

React 19は非同期トランジションでこの問題を解決します。これは、Reactが非同期更新を処理する方法における根本的な変化です。ローディング状態、エラーフラグ、競合状態を手動で管理する代わりに、Reactは保留中の処理を自動的に追跡するようになりました。この記事では、React 19のuseTransitionがReact 18のパターンとどう異なるか、これらのプリミティブをいつ使用すべきか、そしてView Transitions APIのような新しいブラウザAPIとどのように連携するかを解説します。

重要なポイント

  • React 19のstartTransitionは非同期関数を受け入れ、トランジション実行中の保留状態を自動的に追跡します。これにより、手動でのisLoadingの切り替えが不要になります。
  • useTransitionは更新の優先度に関するものであり、アニメーションではありません。フォーム送信、検索フィルター、タブ切り替えに使用し、制御された入力や緊急のエラー状態には使用しないでください。
  • useOptimisticフックは非同期トランジションとうまく連携し、期待される結果を即座に表示し、失敗時には自動的にロールバックします。
  • ReactのスケジューラートランジションとブラウザのView Transitions APIは異なる問題を解決します。前者は更新がいつレンダリングされるかを管理し、後者は要素が状態間でどのようにアニメーションするかを管理します。

startTransitionの非同期サポートがすべてを変える

React 18では、startTransitionは同期関数のみを受け入れていました。状態更新を低優先度としてマークできましたが、非同期操作には別途ローディング状態の管理が必要でした。

React 19はこれを変えました。startTransitionに非同期関数を直接渡せるようになりました:

const [isPending, startTransition] = useTransition()

const handleSubmit = () => {
  startTransition(async () => {
    const result = await saveToServer(data)
    setStatus(result)
  })
}

Reactは非同期アクションの実行中、トランジションを追跡します。isPendingは、Reactがトランジション処理を完了するまでtrueのままです。

重要: await後にスケジュールされた状態更新は、必ずしも同じトランジションに自動的に含まれるとは限りません。これらの更新を非緊急のままにする必要がある場合は、別のstartTransitionでラップしてください。

これにより、React 18のパターンで問題となっていた定型コードの多くが不要になります:

React 18のパターンReact 19のパターン
手動のisLoading状態自動的なisPending追跡
エラー状態を伴うtry/catchエラーバウンダリとの統合
競合状態の処理組み込みのリクエストシーケンス管理

React 19のuseTransition: いつ使用すべきか

高コストな更新中にUIの応答性を維持したい場合にuseTransitionを使用します。このフックはReactに「より緊急な処理が発生した場合、この更新は待機できる」と伝えます。

適切な使用例:

  • ユーザーが入力を続ける可能性があるフォーム送信
  • データ取得をトリガーする検索フィルター
  • 新しいコンテンツを読み込むタブ切り替え

トランジションを使用しない場合:

  • 制御された入力値(これらは即座に更新されるべき)
  • 即座に表示が必要な重要なエラー状態
  • シンプルな同期状態変更

重要な洞察: トランジションは優先度に関するものであり、アニメーションではありません。ユーザーが入力、スクロール、または緊急の操作を行った場合、Reactは保留中のトランジションを中断します。

useOptimisticを使用したReact 19のオプティミスティックUI

useOptimisticフックは非同期トランジションと自然に連携します。サーバーが確認している間に、期待される結果を即座に表示できます:

const [optimisticItems, addOptimistic] = useOptimistic(
  items,
  (current, newItem) => [...current, newItem]
)

const handleAdd = () => {
  startTransition(async () => {
    addOptimistic({ id: "temp", text: inputValue })
    await saveItem(inputValue)
  })
}

リクエストが失敗した場合、Reactは自動的に以前の状態にロールバックします。これにより、複雑な状態調整ロジックなしで、体感パフォーマンスの向上を実現できます。

useOptimisticはトランジションや非同期アクションと併用するのが最適ですが、必須ではありません。データフローに応じて、フックを独立して使用することもできます。

スケジューラートランジション vs. View Transitions API

ReactのトランジションとブラウザのView Transitions APIは異なる問題を解決します:

スケジューラートランジション(useTransition)は、Reactが更新をいつレンダリングするかを管理します。優先度と応答性を処理します。

ビュートランジションは、要素が状態間でどのようにアニメーションするかを管理します。視覚的な連続性を処理します。

Reactは両者を橋渡しする<ViewTransition>コンポーネントを実験中です。ただし、これは実験的なままです。ブラウザAPI自体は、Chrome、Edge、Safari、Firefoxを含む主要ブラウザで広くサポートされています。

現在ビュートランジションを探求している場合:

  • 機能検出と共にdocument.startViewTransition()を使用する
  • サポートされていないブラウザ向けに適切なフォールバックを提供する
  • 本番環境では実験的なフレームワーク統合に依存しない

実践的なガイドライン

推奨:

  • フォーム送信とデータ変更をstartTransitionでラップする
  • isPendingを使用してボタンを無効化し、ローディングインジケーターを表示する
  • 予測可能な操作で即座のフィードバックが必要な場合はuseOptimisticと組み合わせる

非推奨:

  • すべての状態更新をトランジションでラップする
  • バリデーションエラーのような緊急のUIフィードバックにトランジションを使用する
  • View Transitions APIがどこでも動作すると仮定する

まとめ

React 19の非同期トランジションは、React 18アプリケーションで煩雑だった手動のローディング状態ロジックの多くを排除します。startTransitionに非同期関数を渡すことで、組み込みの保留状態追跡、よりスムーズな体感パフォーマンス、そして最新のReactパターンとのより良い統合が得られます。

まず、手動のisLoading状態をuseTransitionに置き換えることから始めましょう。即座のフィードバックが重要な場合はuseOptimisticを追加します。実験的なView Transitions統合は、ブラウザサポートが成熟するまで待ちましょう。

よくある質問

useTransitionはReact Server Componentsで使用できますか?

はい。React 19では、クライアントコンポーネントからトリガーされるServer ActionsをstartTransitionでラップできます。これにより、クライアントから直接サーバー側のミューテーションの保留状態を追跡でき、追加のローディング状態変数なしで自動的なisPending追跡が可能になります。

非同期トランジション中にエラーがスローされた場合はどうなりますか?

トランジション中にスローされたエラーは、存在する場合は最も近いエラーバウンダリに伝播します。エラーバウンダリがない場合、エラーは他のレンダリングエラーと同様に表面化するため、本番アプリではバウンダリが適切に配置されていることを確認する必要があります。useOptimisticによって行われたオプティミスティック更新は、通常、トランジションが中止されるとロールバックされます。

useOptimisticはuseTransitionなしで動作しますか?

はい。トランジションや非同期アクションと一緒に使用されることが多いですが、useOptimisticは単独で機能します。トランジションと組み合わせることで、非緊急更新中の体感応答性が向上するだけです。

すべてのuseStateローディングフラグをuseTransitionに置き換えるべきですか?

必ずしもそうではありません。useTransitionは更新を非緊急としてマークするため、Reactはそのレンダリングを遅延させる可能性があります。インラインバリデーションエラーやモーダルの切り替えなど、即座のUIフィードバックが必要な場合は、シンプルなuseStateブール値が依然として適切な選択です。トランジションは、即時性よりも応答性が重要な操作のために予約してください。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.