対象読者
- 新バージョンでReactを体験してみたい方
- すでにReact開発に従事していて、新機能を知りたい方
- Reactの最新動向を追っておきたい方
なお、本記事はReact 18で導入された「トランジション」や「Suspense」に関して基本知識があることを前提としています。
前提環境
記事のサンプルコードは、以下の環境で動作を確認しています。
- Ubuntu 22.04
- React 19.0.0
- Node.js v22.7.0
- Google Chrome 130.0.6723.92
サンプルコードを実行するには、サンプルのフォルダーでnpm install
コマンドを実行してライブラリーをダウンロードした後、npm start
コマンドを実行し、 https://localhost:3000 をWebブラウザーで表示します。本記事内ではReact 19の新機能に関する本質的な部分を抽出して説明するので、それ以外の実装は各サンプルコードを参照してください。
「アクション」に関連した新しいフック(1)
前回紹介したuseActionState
と<form>
アクション以外にも、React 19では「アクション」に関連した新しいAPIが追加されています。
useOptimisticフック:楽観的更新を簡潔に実現
React 19に新しく追加されたuseOptimistic
フックは、その名の通り「楽観的(Optimistic)な更新」を容易に実装するためのものです。
「楽観的な更新」というのは、「処理に失敗する可能性は低いので、とりあえず画面表示は更新してしまおう」という戦略のことで、ユーザー体験を向上させることが目的です。基本的には以下の流れになります。
- (1)少し時間のかかる処理がある
- (2)処理前に画面表示を期待値にしておく
- (3:処理成功時)処理完了後の値を反映する
- (3:処理失敗時)表示を処理前の値に戻す
こういった動きを実現するためには、処理前後の値・期待値の管理や失敗時のロールバック、成功時の値復元など、意外と複雑な処理が必要になります。これをなるべく容易に実現できるようにしたものがuseOptimistic
フックです。
では前回作成したUpdateTitle
コンポーネントに「楽観的な更新」を追加してみましょう。
function UpdateTitle({ value, onUpdate }) { // useOptimisticで楽観的なステートと更新関数を取得 ... (1) const [optimisticTitle, setOptimisticTitle] = useOptimistic(value); const [error, submitAction, isPending] = useActionState( async (previousState, formData) => { const value = formData.get("title"); // 楽観的な更新を行う ... (2) setOptimisticTitle(value); const { data, error } = await updateTitle(value); if (!error) { onUpdate(data); } return error; }, null //ステートの初期値 ); return ( <form action={submitAction}> <input name="title" defaultValue={value} disabled={isPending} /> <button type="submit" disabled={isPending}> 更新 </button> {error && <p>{error}</p>} <div>値: {value}</div> {/* 楽観的な state を表示する ... (3) */} <div>楽観的な値: {optimisticTitle}</div> </form> ); }
(1)でuseOptimistic
を使い、stateと更新関数を取得しています。このステートは「楽観的なstate」と呼ばれます。
(2)で実際の処理前にステート更新関数を呼び出し、optimisticTitle
を「楽観的に」期待値へ更新します。画面に表示するステートはoptimisticTitle
を指定します((3))。
value
を直接表示している上のほうの値は、非同期関数の完了まで更新されませんが、楽観的なstateであるoptimisticTitle
はボタンを押した直後に更新されます。さらに、非同期関数が成功の場合(error
でなかった場合)はそのまま維持されますが、失敗した場合(error
がある場合;たとえば外部APIとの通信に失敗した場合)は変更前の値に戻ります。
このようにuseOptimistic
を介すだけで「楽観的更新」が実現できます。注目すべきは「変更前の値」も「変更前の値に戻す処理」も「処理完了後の値を反映する処理」も管理する必要がない点です。
[コラム]useOptimisticの使いどころ
いつでも「楽観的更新」が望ましいかというと、そうとも言えません。ここではフォームによる値更新を例に挙げましたが、更新後の値を即座に反映することでユーザーに「更新できた」と誤認させてしまう可能性があります。
「いいねボタン」や「メッセージアプリ」のように、「処理後の状態がフロントエンド側で予測可能」かつ「即時反映されないと体感を損なう」ユースケースで有効なアプローチです。