ReactのAbortControllerでレースコンディションを防ぐ

Webアプリでは、ユーザーの操作は非常に高速です。このスピードが、開発者にとって主に2つの問題を引き起こします。

1つ目の問題は、「アンマウントされたコンポーネントの罠」です。ユーザーがボタンをクリックしてデータを取得します。リクエストには4秒かかるとします。2秒後、ユーザーが「戻る」をクリックしてページを離れます。しかし、リクエストはバックグラウンドで継続されます。データが届いたとき、コードはすでに存在しないコンポーネントを更新しようとします。これがメモリリークの原因となります。

2つ目の問題は「レースコンディション(競合状態)」です。これは検索バーなどで頻繁に発生します。

  • ユーザーが「A」と入力。リクエスト1が開始。
  • ユーザーが「AB」と入力。リクエスト2が開始。
  • リクエスト2が先に完了し、正しいデータが表示される。
  • リクエスト1が遅れて完了し、古いデータで画面が上書きされてしまう。

これら両方の問題は、AbortController APIを使うことで解決できます。このツールを使用すると、不要になったネットワークリクエストを停止できます。

実装方法:

  • useEffect 内で新しい AbortController を作成する。
  • コントローラーの signalfetch リクエストに渡す。
  • try/catch ブロックを使用してエラーを処理する。
  • 意図的なキャンセルを無視するために、エラー名が AbortError であるかを確認する。
  • useEffect でクリーンアップ関数を返し、controller.abort() を呼び出す。

このパターンは、コンポーネントがアンマウントされたときや、依存関係が変更されたときに有効です。

このアプローチのメリット:

  • 古いデータが新しいデータを上書きするのを防げる。
  • Reactアプリ内でのメモリリークを防止できる。
  • ブラウザのネットワーク接続を解放できる。
  • アプリケーションの動作が予測可能で安定した状態を保てる。

Source: https://dev.to/iprajapatiparesh/stop-race-conditions-react-abortcontrollers-2899