NextJS 14使用Firebase短信认证时this.auth.settings未定义问题求助
Firebase OTP认证在NextJS 14中出现
this.auth.settings is undefined错误的解决方法 我在NextJS 14中尝试用Firebase短信OTP实现用户认证,点击Continue按钮调用onSignup函数时触发了this.auth.settings is undefined错误,相关代码和错误截图如下,请求协助解决。
相关代码
app/login/page.js
'use client' import { useState, useRef } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation' import { BiArrowBack } from 'react-icons/bi'; import PhoneInput from 'react-phone-input-2' import 'react-phone-input-2/lib/style.css' import styles from './Login.module.css'; import OTPInput from 'otp-input-react'; import { CgSpinner } from "react-icons/cg"; import { auth } from "../firebase"; import toast, { Toaster } from 'react-hot-toast'; import { RecaptchaVerifier, signInWithPhoneNumber } from "firebase/auth"; import { BsFillShieldLockFill, BsTelephoneFill } from "react-icons/bs"; export default function Login() { const router = useRouter() const [mobileNumber, setMobileNumber] = useState(''); const [verificationId, setVerificationId] = useState(''); const [otp, setOtp] = useState(""); const [loading, setLoading] = useState(false); const [showOTP, setShowOTP] = useState(false); const recaptchaVerifier = useRef(null); const telephone = "+" + mobileNumber; function onCaptchVerify() { if (!window.recaptchaVerifier) { window.recaptchaVerifier = new RecaptchaVerifier( "recaptcha-container", { size: "invisible", callback: (response) => { onSignup(); }, "expired-callback": () => {}, }, auth ); } } function onSignup() { setLoading(true); onCaptchVerify(); const appVerifier = window.recaptchaVerifier; signInWithPhoneNumber(auth, telephone, appVerifier) .then((confirmationResult) => { window.confirmationResult = confirmationResult; setLoading(false); setShowOTP(true); toast.success("OTP sended successfully!"); }) .catch((error) => { console.log(error); setLoading(false); }); } function onOTPVerify() { setLoading(true); window.confirmationResult .confirm(otp) .then(async (res) => { console.log(res); setUser(res.user); setLoading(false); }) .catch((err) => { console.log(err); setLoading(false); }); } return ( <div className={styles.loginBody}> <div className={styles.loginHeader}> <div className={styles.arrow}> <Link href={'/'}><BiArrowBack /></Link> </div> <div className={styles.loginText}> <p>Login/Register</p> </div> <div></div> </div> {showOTP ? ( <> <div className="bg-white text-purple-500 w-fit mx-auto p-4 rounded-full"> <BsFillShieldLockFill size={30} /> </div> <div className="bg-f5f5f5 flex-grow flex flex-col items-center justify-center"> <Toaster position="top-right" reverseOrder={false} toastOptions={{ duration: 2000 }} /> <div className="bg-yellow-100 mx-6 my-12 p-6 rounded-md shadow-lg w-full max-w-md"> <h2 className="text-black text-2xl font-semibold mb-6">Enter OTP</h2> <p className="text-black mb-6">We have sent an OTP to your mobile number.</p> <OTPInput value={otp} onChange={setOtp} OTPLength={6} otpType="number" disabled={false} autoFocus inputClassName="w-full text-purple-500 border-red-500 focus:ring-red-500 focus:border-red-500 rounded-md mx-auto" ></OTPInput> <button onClick={onOTPVerify} className="bg-purple-400 w-full mt-4 flex gap-1 items-center justify-center py-2.5 text-white rounded" > {loading && ( <CgSpinner size={20} className="mt-1 animate-spin" /> )} <span>Verify OTP</span> </button> </div> </div> </> ) : ( <> <div className={styles.loginSubBody}> <div className={styles.mobileNumber}> <PhoneInput country={'in'} value={mobileNumber} onChange={setMobileNumber} /> </div> <div className={styles.continue}> <button onClick={onSignup}>Continue</button> </div> </div> </>)} </div> ); }
firebase.js(已隐藏敏感信息)
// Import the functions you need from the SDKs you need import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; // Your web app's Firebase configuration // For Firebase JS SDK v7.20.0 and later, measurementId is optional const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_MESSAGING_SENDER_ID", appId: "YOUR_APP_ID", measurementId: "YOUR_MEASUREMENT_ID", }; // Initialize Firebase const app = initializeApp(firebaseConfig); export const auth = getAuth(app);
错误截图

问题分析与修复方案
这个错误主要由三个原因导致:缺少Recaptcha挂载容器、Recaptcha初始化时机异步问题、未声明setUser状态。以下是具体修复步骤:
1. 添加Recaptcha容器元素
RecaptchaVerifier需要挂载到指定ID的DOM元素上,即使是隐形模式也必须存在。在登录页面的非OTP显示区域添加容器:
{/* 在showOTP为false的JSX块中添加 */} <div className={styles.loginSubBody}> <div id="recaptcha-container"></div> {/* 新增这行 */} <div className={styles.mobileNumber}> <PhoneInput country={'in'} value={mobileNumber} onChange={setMobileNumber} /> </div> <div className={styles.continue}> <button onClick={onSignup}>Continue</button> </div> </div>
2. 修复Recaptcha初始化与异步逻辑
调整onCaptchVerify为异步函数,确保初始化完成后再调用signInWithPhoneNumber,同时补全setUser的状态声明:
// 新增用户状态声明 const [user, setUser] = useState(null); // 修改onCaptchVerify为异步返回Promise function onCaptchVerify() { return new Promise((resolve) => { if (!window.recaptchaVerifier) { window.recaptchaVerifier = new RecaptchaVerifier( "recaptcha-container", { size: "invisible", callback: (response) => resolve(response), "expired-callback": () => {}, }, auth ); } resolve(window.recaptchaVerifier); }); } // 修改onSignup为async/await处理异步 async function onSignup() { setLoading(true); try { const appVerifier = await onCaptchVerify(); const confirmationResult = await signInWithPhoneNumber(auth, telephone, appVerifier); window.confirmationResult = confirmationResult; setLoading(false); setShowOTP(true); toast.success("OTP发送成功!"); } catch (error) { console.log(error); setLoading(false); toast.error("发送OTP失败,请重试"); } }
3. 额外检查项
- 确认Firebase控制台已启用电话认证方式,并添加了正确的应用域名
- 保持Firebase SDK版本为最新,避免版本兼容问题
- 测试时使用真实手机号码,模拟器无法接收OTP
内容的提问来源于stack exchange,提问作者Sparsh Gahlot
相关产品推荐
相关产品推荐

