ReactのAbortControllerでレースコンディションを防ぐ
Webアプリでは、ユーザーの操作は非常に高速です。このスピードが、開発者にとって主に2つの問題を引き起こします。
1つ目の問題は、「アンマウントされたコンポーネントの罠」です。ユーザーがボタンをクリックしてデータを取得します。リクエストには4秒かかるとします。2秒後、ユーザーが「戻る」をクリックしてページを離れます。しかし、リクエストはバックグラウンドで継続されます。データが届いたとき、コードはすでに存在しないコンポーネントを更新しようとします。これがメモリリークの原因となります。
2つ目の問題は「レースコンディション(競合状態)」です。これは検索バーなどで頻繁に発生します。
- ユーザーが「A」と入力。リクエスト1が開始。
- ユーザーが「AB」と入力。リクエスト2が開始。
- リクエスト2が先に完了し、正しいデータが表示される。
- リクエスト1が遅れて完了し、古いデータで画面が上書きされてしまう。
これら両方の問題は、AbortController APIを使うことで解決できます。このツールを使用すると、不要になったネットワークリクエストを停止できます。
実装方法:
useEffect内で新しいAbortControllerを作成する。- コントローラーの
signalをfetchリクエストに渡す。 try/catchブロックを使用してエラーを処理する。- 意図的なキャンセルを無視するために、エラー名が
AbortErrorであるかを確認する。 useEffectでクリーンアップ関数を返し、controller.abort()を呼び出す。
このパターンは、コンポーネントがアンマウントされたときや、依存関係が変更されたときに有効です。
このアプローチのメリット:
- 古いデータが新しいデータを上書きするのを防げる。
- Reactアプリ内でのメモリリークを防止できる。
- ブラウザのネットワーク接続を解放できる。
- アプリケーションの動作が予測可能で安定した状態を保てる。
Source: https://dev.to/iprajapatiparesh/stop-race-conditions-react-abortcontrollers-2899