エラー時のロールバックと競合解決
Mutationが失敗したときに以前の状態を復元し、サーバーに拒否された楽観的変更を適切に処理します
「エラー時のロールバックと競合解決」はCoddyKit上の無料React Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
ロールバックの複雑さはミューテーションの種類に応じて増す
楽観的な追加のロールバック(アイテムを削除)や削除のロールバック(アイテムを復元)は簡単です。一方、更新のロールバックはより複雑です。正確な以前の値を復元する必要があるためです。アイテムが楽観的に複数回更新されている場合は、元のサーバー状態だけでなく、以前の各値を個別に追跡する必要があります。
更新の競合が発生する状況
次の状況を考えてみてください。サーバー上のアイテムの値は Z です。そこから、楽観的に X へ更新します。リクエストの実行中に、別のユーザーがサーバー上の同じアイテムを Y に更新しました。あなたのリクエストが到着すると、サーバーはそれを競合として拒否します。ロールバック先は Z ですが、サーバーの現在の状態は Y です。Z に戻すと、Y が誤って上書きされてしまいます。
エラー時の再取得を安全なデフォルトにする
更新に対する最も安全なロールバック戦略は、ローカルで取得したスナップショットを復元するのではなく、ミューテーションでエラーが発生したらサーバーからアイテムを再取得することです。これにより、他のユーザーが同時に変更を加えていても、信頼できるサーバーの状態を表示できます。再取得は遅くなりますが、常に正しい状態になります。
HTTP 409 Conflict ステータス
適切に設計された API は、同時変更が原因で楽観的更新に失敗した場合、HTTP 409 Conflict を返します。レスポンスボディには通常、サーバー上の現在の状態が含まれます。エラーハンドラーでは 409 を検出し、レスポンスボディを使ってローカル状態をサーバーの現在値に更新し、変更が保存されなかったことをユーザーに通知します。
安全な再試行のための冪等性
冪等なミューテーションは、複数回適用しても同じ結果になります。ミューテーションを冪等になるように設計すると(POST の代わりに PUT を使う、リソースの完全な状態を含める、冪等性キーを使うなど)、変更を二重に適用する心配なく、失敗時に安全に再試行できます。これにより、ロールバックのロジックが大幅に簡単になります。
isSubmitting による重複排除
送信ボタンのダブルクリックによって、同一のミューテーションが 2 回実行されることがあります。これを防ぐには isSubmitting フラグを使います。ミューテーションの開始時に true に設定し、成功・失敗を問わず完了時にリセットします。isSubmitting が true の間は、トリガー要素を無効にします。これにより、UI レベルで重複したミューテーションを排除できます。
サーバー側の重複排除のための冪等性キー
サーバー側で重複排除するには、各ミューテーションリクエストに一意の Idempotency-Key ヘッダーを含めます。ユーザーが操作を開始した時点で crypto.randomUUID() を使って生成します。サーバーは重複したキーを検出すると、操作を再適用せず、元のリクエストと同じレスポンスを返します。
結果整合性のインジケーター
ミューテーションの実行中は、楽観的な状態がまだ確定していないことを示す控えめなインジケーターを表示できます。たとえば、小さく点滅するドット、「保存中…」というテキスト、またはアイテムの不透明度を下げる表示などです。操作を妨げずに、不確実な状態であることを伝えられます。成功時にインジケーターを消し、失敗時にはロールバックします。
ミューテーションの失敗に対するエラーバウンダリ
ロールバックロジックで予期しないエラーが発生すると(たとえば、状態の復元中に undefined のプロパティへアクセスするなど)、コンポーネントがクラッシュすることがあります。ミューテーションを多用するコンポーネントをエラーバウンダリで囲み、重大なロールバックの失敗が発生しても、空白の画面ではなく適切なエラー UI を表示できるようにします。デバッグできるよう、これらのエラーをログに記録してください。
競合検出のためのバージョン管理
信頼性の高い競合検出戦略では、すべてのミューテーションにバージョン番号または ETag を含めます。サーバーは、クライアントから送られたバージョンと現在のバージョンを比較します。両者が異なる場合(別の更新が発生した場合)は、409 を返します。これは楽観的同時実行制御です。競合は発生しないと想定し、発生した時点で検出します。
ロールバック経路のテスト
ネットワーク障害は再現しにくいため、ロールバックロジックはテストされないことがよくあります。Mock Service Worker(MSW)のようなツールを使い、テストでエラーレスポンスを返すようにしてください。409 Conflict の処理、ネットワークタイムアウト時のロールバック、ダブルクリックによる重複排除、失敗後の状態の整合性について、明示的なテストを作成します。こうしたエッジケースにバグが潜んでいます。
競合検出に使う HTTP ステータス
別のユーザーによる同時変更が原因で楽観的更新に失敗した場合、適切に設計された API はどの HTTP ステータスコードを返しますか
レッスンのまとめ:ロールバックと競合
更新のロールバックは追加や削除よりも複雑です。古いスナップショットの問題を避けるため、エラー時は必ず再取得してください。HTTP 409 Conflict は楽観的同時実行制御の失敗を示すため、レスポンスボディを使ってサーバーの現在の状態に戻します。安全に再試行できるよう、ミューテーションは冪等になるように設計します。isSubmitting とサーバー側の冪等性キーを使って二重実行を防ぎます。MSW でエラーをシミュレートし、ロールバック経路を明示的にテストしてください。
よくある質問
「エラー時のロールバックと競合解決」レッスンは無料ですか?
はい。「エラー時のロールバックと競合解決」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「エラー時のロールバックと競合解決」で何を学びますか?
Mutationが失敗したときに以前の状態を復元し、サーバーに拒否された楽観的変更を適切に処理します ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「エラー時のロールバックと競合解決」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 楽観的UIとは何か、いつ使うか
- 楽観的更新の手動実装
- エラー時のロールバックと競合解決
- React QueryとZustandによる楽観的更新パターン