React HooksにおけるStale Closure(古いクロージャ)の修正方法

ReactのuseEffectフックでタイマーを作成しているとします。5秒ごとにドキュメントを自動保存したいと考えています。タイマーは動作していますが、空のドキュメントを保存してしまいます。ユーザーは10段落も入力したのに、タイマーには何も見えていないのです。

これがStale Closure(古いクロージャ)です。

useEffectフックは、最初のレンダリング時の変数をキャプチャします。もし依存関係配列(dependency array)からステートを除外してしまうと、タイマーは過去の状態に留まったままになります。つまり、データの古いバージョンを使用してしまうのです。

もし依存関係配列にステートを追加すると、ユーザーが1文字入力するたびにタイマーがリセットされてしまいます。これではパフォーマンスが低下し、タイミングのロジックも崩れてしまいます。

これを解決するのがMutable Ref Patternです。

useRefフックを使用して、最新のステートを保持します。これにより、新しいレンダリングをトリガーしたりインターバルをリセットしたりすることなく、タイマーが最新のデータにアクセスできるようになります。

次の手順に従ってください:

このアプローチにより、タイマーとデータが切り離されます。バックグラウンドタスクは安定し、データは正確なまま保たれます。

サイレントなバグによってユーザーデータを失うのはもうやめましょう。refを使用して、非同期タスクをUIと同期させましょう。

出典: https://dev.to/iprajapatiparesh/escaping-the-trap-fixing-stale-closures-in-react-hooks-4gg7