罠を回避する:React HooksにおけるStale Closureの修正方法
Stale Closureは、Reactにおいてサイレントなデータ損失を引き起こします。
バックグラウンドタイマーを備えたダッシュボードを構築するとしましょう。useEffectフック内でsetIntervalを使用し、5秒ごとにデータを自動保存するようにします。
バグは、インターバルが実行されるときに発生します。ユーザーがページ全体を入力したとしても、空のドキュメントが保存されてしまうのです。インターバルは過去の状態に留まったままになり、古いバージョンのステートを使用してしまいます。
問題点
useEffectが実行されるとき、そのスコープ内の変数がキャプチャされます。
- 依存関係配列(dependency array)からステートを除外すると、インターバルは初回レンダリング時のステートを使用します。
- 依存関係配列にステートを追加すると、キー入力のたびにReactがインターバルを再起動してしまいます。これによりパフォーマンスが低下し、タイミングが崩れてしまいます。
解決策:Mutable Refパターン
タイマーとデータを分離する必要があります。useRefフックを使用して、最新のステートへの一定の参照を保持します。これにより、再レンダリングを回避し、インターバルを安定させることができます。
実装方法:
- 最新のステートを保持するためのrefを作成します。
- ステートが変更されるたびに、そのrefを更新する
useEffectを使用します。 - インターバルは空の依存関係配列で開始し、一度だけ実行されるようにします。
- インターバルのコールバック内でrefにアクセスします。
この方法により、バックグラウンドタスクが常に最新のデータを使用することが保証されます。UIの速度を維持しつつ、データを安全に保つことができます。
出典: https://dev.to/iprajapatiparesh/escaping-the-trap-fixing-stale-closures-in-react-hooks-4gg7