「ボタンを押したのに、グルグル(ローディング)が回って待たされる」
私たちはこれを当たり前だと思っていますが、
ユーザーにとっては「人生の貴重な時間を奪われている」のと同義です。
Amazonの調査では、表示速度が0.1秒遅れるだけで売上が1%下がると言われています。
0.1秒の「待ち」は、ビジネスにおける損失なのです。
では、どうすれば「待ち時間ゼロ」を実現できるのか? サーバーを光の速さにする必要はありません。
「見せ方(UI)」を変えるだけでいいのです。
本記事では、InstagramやTwitterが採用している「Optimistic UI(楽観的UI)」の概念と、React/Next.jsを用いた具体的な実装パターンを解説します。
1. 心理学:「サーバーの正解」より「ユーザーの体感」
従来のWeb開発の常識はこうでした。
「Pessimistic UI(悲観的UI)」
- ユーザーがボタンを押す。
- ローディングを表示する(ぐるぐる…)。
- サーバーに通信し、DB書き込み完了を待つ。
- 成功が返ってきたら、画面を更新する。
これはエンジニアにとっては誠実ですが、UXとしては**「サーバーの都合でユーザーを待たせている」**状態です。
対して、今のトレンドはこうです。
「Optimistic UI(楽観的UI)」
- ユーザーがボタンを押す。
- 即座に「成功した」と画面を切り替える。
- 裏でこっそりサーバーと通信する。
「もし失敗したらどうするの?」と思うでしょう。その確率は(設計によりますが)1%未満です。
99%の成功ケースのために、全員を待たせる必要はない。
これがOptimistic UIの思想です。
2. 実装編:Reactで書く「未来の先取り」
言葉だけではイメージしづらいので、具体的なコード(React)で比較してみましょう。 「いいねボタン」を押す処理を例にします。
❌ 従来の書き方 (悲観的UI)
サーバーからのレスポンス(await)を待ってから、State(画面)を更新しています。
これが「体感の遅さ」の正体です。
例)JavaScript
const handleLike = async () => {
setIsLoading(true); // 1. ローディング開始
try {
// 2. サーバー通信 (ここで数秒待たされる!)
await api.post('/like', { id: postId });
// 3. 成功してから画面更新
setLiked(true);
} catch (err) {
alert('エラー');
} finally {
setIsLoading(false); // 4. ローディング終了
}
};
✅ Optimistic UIの書き方 (楽観的UI)
API通信の結果を待たず、先にStateを更新しています。
例)JavaScript
const handleLikeOptimistic = () => {
// 0. 現在の状態をバックアップ (ロールバック用)
const previousState = liked;
// 1. サーバーを待たず、即座に「いいね!」にする (爆速UX)
setLiked(true);
// 2. 裏側で通信 (Fire-and-Forget)
api.post('/like', { id: postId })
.catch((err) => {
// 3. 万が一失敗したら、しれっと元に戻す (ロールバック)
console.error('Like failed', err);
setLiked(previousState);
// 必要ならToast通知などで「反映できませんでした」と伝える
showErrorToast();
});
};
このコードにより、ユーザーはボタンを押した瞬間にフィードバックを得られ、
「このアプリ、サクサク動くぞ!」という快感を感じます。
3. プロの道具箱:SWR / TanStack Query の活用
実務でOptimistic UIを実装する場合、上記のように手動でState管理をすると複雑になりがちです。 モダンなフロントエンド開発では、SWR や TanStack Query (React Query) というライブラリを使うのが標準です。
これらには optimisticData という専用のオプションが用意されています。
例)JavaScript
// SWRを使った例
import useSWR, { mutate } from 'swr';
const { data } = useSWR('/api/user');
const updateProfile = async (newName) => {
// mutate(キー, 新しいデータ, 再検証するか)
mutate('/api/user', { ...data, name: newName }, false); // ★ここがOptimistic UI
// 裏でAPIを叩く
await api.updateName(newName);
// 完了したら正しいデータを再取得して整合性をとる
mutate('/api/user');
};
4. アーキテクチャとの結合:AWS SQS との相性
このフロントエンド技術は、以前の記事で解説した「AWS非同期ログ基盤(SQS)」と組み合わせることで最強の効果を発揮します。
- Frontend (Optimistic): 画面を即座に完了させる。
- Network (Fire-and-Forget): APIリクエストを投げるが、レスポンスを待たない(あるいは202 Acceptedだけ受け取る)。
- Backend (SQS): AWS側でリクエストをキュー(行列)に入れ、非同期でゆっくり処理する。
この構成なら、「フロントエンドは爆速」かつ「バックエンドはスパイクに強い」
という、攻守最強のアプリケーションが完成します。
5. 導入してはいけないケース (注意点)
Optimistic UIは魔法ですが、万能ではありません。以下のケースでは使用を避けてください。
- 決済処理: 「購入完了」と出した後に「カードエラーでした」と戻すのは、ユーザーの信頼を著しく損ないます。
- 在庫確保: チケット予約など、ダブルブッキングが許されない処理。
逆に、以下の機能は今すぐOptimistic UIにすべきです。
- いいね / ブックマーク
- ToDoリストの追加・削除
- 下書き保存
- カートへの追加(※在庫チェックが厳密でない場合)
まとめ:UXは「技術」で作れる
「サイトが重い」「反応が遅い」 これは、回線速度の問題ではありません。
実装のアプローチ(設計思想)の問題です。
サーバーの処理が終わるのを、律儀に待つ必要はありません。
「成功を信じて、先に進める」。
この楽観的なアプローチこそが、ユーザーを待ち時間のストレスから解放し、プロダクトの価値を最大化します。
👇 【あわせて読みたい】「裏側」はどうなっている?
【AWS】UXを爆速にする「非同期処理」アーキテクチャ
フロントエンドが「楽観的」に投げたデータを、バックエンドで確実に受け止める「SQS × Lambda」の構成を解説しています。
👇 【キャリア】UIとインフラ両方を設計できる人材へ
【年収1000万への道】「機能を作る人」から「ビジネスを救う人」へ
Next.js (フロント) と AWS (インフラ) の両方を理解し、最適なUXを設計できるアーキテクチャ・スキル。 それをどうキャリアに活かすか解説します。

コメント