shwldshwlda month ago

データフェッチ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では特に重要。未認証時のリダイレクト判定が古いレスポンスに基づくと、チラつきやリダイレクトループの原因になる