React HooksにおけるStale Closure(古いクロージャ)の修正方法
ReactのuseEffectフックでタイマーを作成しているとします。5秒ごとにドキュメントを自動保存したいと考えています。タイマーは動作していますが、空のドキュメントを保存してしまいます。ユーザーは10段落も入力したのに、タイマーには何も見えていないのです。
これがStale Closure(古いクロージャ)です。
useEffectフックは、最初のレンダリング時の変数をキャプチャします。もし依存関係配列(dependency array)からステートを除外してしまうと、タイマーは過去の状態に留まったままになります。つまり、データの古いバージョンを使用してしまうのです。
もし依存関係配列にステートを追加すると、ユーザーが1文字入力するたびにタイマーがリセットされてしまいます。これではパフォーマンスが低下し、タイミングのロジックも崩れてしまいます。
これを解決するのがMutable Ref Patternです。
useRefフックを使用して、最新のステートを保持します。これにより、新しいレンダリングをトリガーしたりインターバルをリセットしたりすることなく、タイマーが最新のデータにアクセスできるようになります。
次の手順に従ってください:
- ステートを保持するためのrefを作成する。
useEffectを使用して、refとステートを同期させる。- インターバルを空の依存関係配列で設定し、一度だけ実行されるようにする。
- インターバルのコールバック内でrefにアクセスする。
このアプローチにより、タイマーとデータが切り離されます。バックグラウンドタスクは安定し、データは正確なまま保たれます。
サイレントなバグによってユーザーデータを失うのはもうやめましょう。refを使用して、非同期タスクをUIと同期させましょう。
出典: https://dev.to/iprajapatiparesh/escaping-the-trap-fixing-stale-closures-in-react-hooks-4gg7