データフェッチhookでignoreフラグによるrace conditionを防ぐ
Reactで認証状態やユーザー情報をフェッチするカスタムhookを作るとき、コンポーネントのアンマウントや再レンダリングによるrace conditionを防ぐには、useEffectのクリーンアップでignoreフラグを使う。
function useCurrentUser() {
const [user, setUser] = useState<User | null>(null)
useEffect(() => {
let ignore = false
fetch('/api/auth/me')
.then(res => res.json())
.then(data => {
if (!ignore) setUser(data)
})
return () => { ignore = true }
}, [])
return user
}
ポイント:
ignoreフラグにより、アンマウント後のsetStateが抑制される。React 18のStrict Modeでは開発時にuseEffectが2回実行されるため、このパターンがないと古いレスポンスで状態が上書きされる- AbortControllerでfetchをキャンセルする方法もあるが、ignoreフラグの方がシンプルで、fetch以外の非同期処理にも使える
- 認証チェックのようにページ遷移のたびに呼ばれるhookでは特に重要。未認証時のリダイレクト判定が古いレスポンスに基づくと、チラつきやリダイレクトループの原因になる