From 09562776d42473c421b7a3428aee58bef38e5f45 Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:43:52 +0800 Subject: [PATCH] fix(web): avoid setState in useEffect in AuthGuard --- apps/web/components/auth-guard.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/web/components/auth-guard.tsx b/apps/web/components/auth-guard.tsx index ed17c329..a7e00773 100644 --- a/apps/web/components/auth-guard.tsx +++ b/apps/web/components/auth-guard.tsx @@ -1,6 +1,6 @@ 'use client' -import { useEffect, useState } from 'react' +import { useLayoutEffect, useState } from 'react' import { useRouter } from 'next/navigation' import { isAuthenticated } from '@/lib/auth' @@ -10,19 +10,20 @@ interface AuthGuardProps { export function AuthGuard({ children }: AuthGuardProps) { const router = useRouter() - const [isChecking, setIsChecking] = useState(true) - const [isAuthed, setIsAuthed] = useState(false) + // Initialize state synchronously to avoid cascading renders + const [authState] = useState(() => { + if (typeof window === 'undefined') return { checking: true, authed: false } + const authed = isAuthenticated() + return { checking: false, authed } + }) - useEffect(() => { - if (isAuthenticated()) { - setIsAuthed(true) - } else { + useLayoutEffect(() => { + if (!authState.checking && !authState.authed) { router.replace('/login') } - setIsChecking(false) - }, [router]) + }, [authState, router]) - if (isChecking) { + if (authState.checking) { return (
@@ -30,7 +31,7 @@ export function AuthGuard({ children }: AuthGuardProps) { ) } - if (!isAuthed) { + if (!authState.authed) { return null }