Next 13 App Router+Typescript+Firebase路由保护问题求助
Next 13 App Router + Firebase 路由保护问题解决方案
问题根源分析
- 布局层级错误:原代码中
ProtectedRoutes包裹了AuthProvider,导致组件渲染时useAuth无法立即获取认证状态,isLoading初始状态未正确拦截,造成未登录用户短暂看到首页后才跳转。 - 路由规则不完整:仅处理了未登录用户的跳转逻辑,未限制已登录用户访问
/login路由。 - 无加载占位:认证状态加载过程中直接渲染页面内容,引发闪屏。
解决方案步骤
1. 调整布局层级,确保Auth上下文优先加载
修改src/app/layout.tsx,将AuthProvider放在最外层,保证ProtectedRoutes能获取完整的认证状态:
import { AuthProvider } from '@/hooks/useAuth'; import '../styles/globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import ProtectedRoutes from '@/components/ProtectedRoutes'; const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { title: 'Proposals Mayara Dev', description: 'Proposals System Mayara Becker Dev', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body suppressHydrationWarning={true} className={inter.className}> <AuthProvider> <ProtectedRoutes> {children} <ToastContainer position='bottom-right' /> </ProtectedRoutes> </AuthProvider> </body> </html> ) }
2. 重构ProtectedRoutes组件,完善路由规则
更新ProtectedRoutes.tsx,增加路由判断逻辑,同时在认证加载过程中显示占位组件(避免闪屏):
"use client" import { useEffect } from 'react'; import { useRouter, usePathname } from 'next/navigation'; import { useAuth } from '@/hooks/useAuth'; // 可自定义加载组件,比如Spinner const Loading = () => <div>Loading...</div>; const ProtectedRoutes = ({ children }: { children: React.ReactNode }) => { const { isLoggedIn, isLoading } = useAuth(); const router = useRouter(); const pathname = usePathname(); useEffect(() => { if (isLoading) return; // 已登录用户访问/login,跳转到首页 if (isLoggedIn && pathname === '/login') { router.push('/'); return; } // 未登录用户访问非/login路由,跳转到/login if (!isLoggedIn && pathname !== '/login') { router.push('/login'); } }, [isLoggedIn, isLoading, router, pathname]); // 加载过程中显示占位,阻止渲染页面内容 if (isLoading) { return <Loading />; } // 已登录或当前是/login页面(未登录状态),渲染内容 return <>{children}</>; }; export default ProtectedRoutes;
3. 确保useAuth Hook的状态初始化正确
检查useAuth Hook,确保isLoading初始值为true,直到Firebase Auth完成初始化:
// 示例useAuth Hook核心逻辑 "use client" import { useState, useEffect } from 'react'; import { getAuth, onAuthStateChanged, User } from 'firebase/auth'; export const useAuth = () => { const [user, setUser] = useState<User | null>(null); const [isLoading, setIsLoading] = useState(true); // 初始为true useEffect(() => { const auth = getAuth(); const unsubscribe = onAuthStateChanged(auth, (user) => { setUser(user); setIsLoading(false); // 初始化完成后设为false }); return unsubscribe; }, []); return { isLoggedIn: !!user, user, isLoading }; };
关键注意事项
- 避免重复跳转:通过
pathname判断当前路由,防止无限循环跳转。 - 加载占位:认证状态未确定时,必须阻止页面内容渲染,彻底解决闪屏问题。
- Firebase Auth初始化:确保
onAuthStateChanged正确监听状态,且isLoading在初始化完成后才切换为false。
内容的提问来源于stack exchange,提问作者Elton Santos
相关产品推荐
相关产品推荐

