Next.js中Firebase邮箱密码登录报错问题排查
问题根源及修复方案
核心错误:window is not defined
报错明确指向Firebase配置文件在服务端渲染时访问了window对象——Next.js的App Router默认会对页面进行服务端渲染(SSR),而服务端环境不存在window。你的Firebase初始化代码里大概率直接在服务端执行了依赖浏览器环境的逻辑(比如Analytics初始化)。
修复Firebase配置文件
修改@/app/firebase/config.js,确保仅在客户端环境初始化Firebase,并且避免在服务端加载Analytics:
// app/firebase/config.js import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; const firebaseConfig = { // 你的Firebase配置信息 }; // 仅在客户端环境初始化Firebase相关服务 let app; let auth; if (typeof window !== "undefined") { app = initializeApp(firebaseConfig); auth = getAuth(app); // 按需初始化Analytics,仅在支持的环境加载 import("firebase/analytics").then(({ getAnalytics, isSupported }) => { isSupported().then((supported) => { if (supported) getAnalytics(app); }); }); } export { auth };
登录逻辑优化与跳转修复
除了Firebase初始化问题,同步优化登录逻辑确保跳转正常:
- 利用
react-firebase-hooks返回的状态直接监听登录结果,替代try/catch更符合hooks使用习惯 - 确保登录成功后再执行跳转逻辑
修改后的登录页面代码:
'use client' import { useState } from 'react'; import { useSignInWithEmailAndPassword } from 'react-firebase-hooks/auth' import { auth } from '@/app/firebase/config' import { useRouter } from 'next/navigation'; const SignIn = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [signInWithEmailAndPassword, user, loading, error] = useSignInWithEmailAndPassword(auth); const router = useRouter() const handleSignIn = async () => { await signInWithEmailAndPassword(email, password); }; // 登录成功后自动跳转首页 if (user) { sessionStorage.setItem('user', JSON.stringify(user)); router.push('/'); } return ( <div className="min-h-screen flex items-center justify-center bg-gray-900"> <div className="bg-gray-800 p-10 rounded-lg shadow-xl w-96"> <h1 className="text-white text-2xl mb-5">Sign In</h1> {error && <p className="text-red-400 mb-4">{error.message}</p>} <input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} className="w-full p-3 mb-4 bg-gray-700 rounded outline-none text-white placeholder-gray-500" disabled={loading} /> <input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} className="w-full p-3 mb-4 bg-gray-700 rounded outline-none text-white placeholder-gray-500" disabled={loading} /> <button onClick={handleSignIn} className="w-full p-3 bg-indigo-600 rounded text-white hover:bg-indigo-500 disabled:bg-indigo-800" disabled={loading} > {loading ? 'Signing In...' : 'Sign In'} </button> </div> </div> ); }; export default SignIn;
额外注意事项
- 所有依赖浏览器API(如
window、sessionStorage)的代码必须放在标记了'use client'的组件内 - 避免在服务端执行任何仅浏览器支持的Firebase服务初始化逻辑
内容的提问来源于stack exchange,提问作者Ajay Satpati
相关产品推荐
相关产品推荐

