Next.js/レンダリング/Lesson 08
Optimistic UI — useActionState + useFormStatus + useOptimistic
35分·theory
このチャプター
5/5
TypeScript
Optimistic UI — useActionState + useFormStatus + useOptimistic
💡 なぜ学ぶべきか? — 「クリック後のわずかな待ち」がなくなる
🎯
いいねボタンを押してからサーバーの応答(200〜500ms)を待ってUIが変わると、ユーザーは「ちゃんと押せたのかな?」と不安になります。
💼
Optimistic UI:クリック直後にUIを「成功したかのように」表示し、サーバーの応答が返ってきたら実際の結果を反映。失敗した場合は自動ロールバック。
⚡
React 19の`useOptimistic`フックによってこのパターンが標準化されました — TwitterやInstagramのいいねのような即時反応UXを実現します。
🔗
`useActionState`(旧useFormState)+ `useFormStatus` + `useOptimistic` の3つのフックが合わさることで、Server Actionのフォー厶UXが完成します。
📈
ユーザー体験として:クリック直後にレスポンス → 本当に速いアプリという印象。
🏢 실무에서는
いいね・ブックマーク・フォロー・カート追加 — ユーザーが毎日何十回もクリックするアクションです。毎回0.3秒の待ちが積み重なると「遅いサイト」という印象につながります。`useOptimistic`を使えばクリック直後にカウント+1を表示し、サーバーから実際の結果が返ってきたら照合。失敗時は-1を自動ロールバックしてエラーメッセージを表示します。
3つの hook — 役割分担
1. 各 hook の役割
2. useActionState(React 19 — 旧 useFormState の代替)
Action のシグネチャが (prevState, formData) => newState に変わります。
3. useFormStatus — 子要素が親 form の状態を読み取る
親の <form> 内のどこにでも配置すれば、自動的にそのフォームの状態を取得できます。props のバケツリレー不要。
4. useOptimistic — 即座の UI 更新 + 自動ロールバック
5. 3つを組み合わせる — 完成したフォーム
💡 💡 Optimistic UI 実践 5 つのポイント
1. useOptimistic は startTransition 内で呼び出す
Transition なしで呼び出すと同期更新になり、効果が薄くなります。
2. optimistic 項目に pending: true などのマーカーを付ける
「まだサーバーで確認されていない」という視覚的シグナルをユーザーに提供(opacity 0.5、「送信中」ラベルなど)。
3. 失敗時の追加コード不要 — React が自動ロールバック
Server Action が throw した場合、optimistic state は破棄され元の値が復元されます。catch でエラートーストを追加するだけで十分。
4. revalidatePath 後に実際の値が届いたら自動同期
Server Action の末尾で revalidatePath を呼び出す → ページデータを再取得 → useOptimistic の initial 値が更新 → optimistic が自動破棄。
5. useActionState と組み合わせる — フォーム全体の状態管理
⚡ 実際に試してみる — Optimistic UI シナリオ
成功・失敗のケースで optimistic state がどのように動作するかをシミュレーションします。
✏️ JS 코드
📟 コンソール出力
▶ 実行ボタンを押してください
⚠️ ブラウザのサンドボックスで実行 — console.log()のみ対応、alert/fetchは不可
理解度チェック
Server Action を呼び出した後にサーバーのレスポンスが失敗した場合、useOptimistic の値はどうなりますか?
先に読むとよい概念: Streaming + Suspense — 段階的HTMLストリーミング