You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React集成Firebase发送OTP时出现TypeError的问题排查与解决

React + Firebase 手机号OTP验证报错问题

我在React项目中用Firebase实现手机号OTP验证,手机号从其他组件传入。点击发送OTP时出现错误:TypeError: Cannot read properties of undefined (reading 'verify')。相关代码如下:

OtpVerification.js

import React, { useState } from 'react';
import { auth, } from '../firebase';
import { signInWithPhoneNumber } from 'firebase/auth';

const OtpVerification = ({ phoneNumber }) => {
  const [otp, setOtp] = useState('');
  const [verificationId, setVerificationId] = useState(null);

  const onSendOtp = () => {
    // Ensure that the phone number is valid before sending OTP
    if (!phoneNumber) {
      console.error('Invalid phone number');
      return;
    }
    const appVerifier = window.recaptchaVerifier;
    // Send OTP to the provided phone number
    signInWithPhoneNumber(auth, `+${phoneNumber}`, appVerifier)
      .then((confirmationResult) => {
        // Save the verification ID to use later for OTP confirmation
        // setVerificationId(confirmationResult.verificationId);
        window.confirmationResult = confirmationResult;
        console.log('OTP sent successfully');
        // Additional logic if needed
      })
      .catch((error) => {
        console.error('Error sending OTP:', error);
        // Handle error appropriately
      });
  };

  const onVerify = () => {
    if (!verificationId || !otp) {
      console.error('Invalid verification ID or OTP');
      return;
    }

    // Confirm the OTP using the verification ID
    signInWithPhoneNumber(auth, verificationId, otp)
      .then((result) => {
        console.log('Phone number verified successfully:', result);
        // Additional logic if needed
      })
      .catch((error) => {
        console.error('Error verifying OTP:', error);
        // Handle error appropriately
      });
  };

  return (
    <div className='otpVerification'>
      <input
        type='number'
        value={otp}
        onChange={(e) => setOtp(e.target.value)}
        maxLength={6}
      />
      <button onClick={onSendOtp}>Send OTP</button>
      <button onClick={onVerify}>Verify</button>
    </div>
  );
};

export default OtpVerification;

firebase.js

import { initializeApp } from "firebase/app";
import {getDatabase} from 'firebase/database';
import { getAuth } from "firebase/auth";


const firebaseConfig = {
  apiKey: "",
  authDomain: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: "",
  appId: ""
};



const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getDatabase(app);

export {auth,db};

问题:

  1. 该错误的成因是什么?
  2. 如何解决?
  3. 还有其他更简便的React OTP验证实现方式吗?

错误成因

这个报错的核心原因是**window.recaptchaVerifier未被正确初始化**。Firebase手机号验证强制要求搭配reCAPTCHA验证防止机器人请求,你直接从window对象获取它,但实际没有提前创建并渲染reCAPTCHA实例,导致appVerifier为undefined,最终调用signInWithPhoneNumber时内部尝试访问它的verify方法触发报错。

另外onVerify方法存在API误用:验证OTP应该调用confirmationResult.confirm(otp),而非再次调用signInWithPhoneNumber——后者是用来发起发送OTP请求的,不是验证OTP的接口。

解决方法

1. 正确初始化reCAPTCHA

在组件加载时创建reCAPTCHA实例,确保DOM中存在对应的渲染容器:

import React, { useState, useEffect } from 'react';
import { auth, } from '../firebase';
import { signInWithPhoneNumber } from 'firebase/auth';

const OtpVerification = ({ phoneNumber }) => {
  const [otp, setOtp] = useState('');
  const [confirmationResult, setConfirmationResult] = useState(null);

  useEffect(() => {
    // 初始化reCAPTCHA实例
    window.recaptchaVerifier = new auth.RecaptchaVerifier('recaptcha-container', {
      'size': 'invisible', // 可选:invisible/normal/compact
      'callback': () => {
        // reCAPTCHA验证成功回调,可留空
      }
    }, auth);
  }, []);

  const onSendOtp = () => {
    if (!phoneNumber) {
      console.error('无效的手机号');
      return;
    }
    const appVerifier = window.recaptchaVerifier;
    signInWithPhoneNumber(auth, `+${phoneNumber}`, appVerifier)
      .then((result) => {
        setConfirmationResult(result); // 保存验证结果实例,无需存到window
        console.log('OTP已发送');
      })
      .catch((error) => {
        console.error('发送OTP失败:', error);
        // 重置reCAPTCHA实例避免重复报错
        window.recaptchaVerifier.reset();
      });
  };

  const onVerify = () => {
    if (!confirmationResult || !otp) {
      console.error('验证实例或OTP无效');
      return;
    }

    // 用正确的API验证OTP
    confirmationResult.confirm(otp)
      .then((result) => {
        console.log('手机号验证成功:', result.user);
        // 此处可获取验证后的用户对象,处理后续逻辑
      })
      .catch((error) => {
        console.error('验证OTP失败:', error);
        window.recaptchaVerifier.reset();
      });
  };

  return (
    <div className='otpVerification'>
      {/* 必须添加reCAPTCHA渲染容器 */}
      <div id="recaptcha-container"></div>
      <input
        type='number'
        value={otp}
        onChange={(e) => setOtp(e.target.value)}
        maxLength={6}
      />
      <button onClick={onSendOtp}>发送OTP</button>
      <button onClick={onVerify}>验证</button>
    </div>
  );
};

export default OtpVerification;

2. 确保手机号格式正确

传入的phoneNumber需包含正确国家码前缀(或在代码中拼接正确的国家码),比如8613xxxxxxxxx,避免格式错误导致请求失败。

更简便的React OTP验证实现方式

1. 使用Firebase UI Auth

Firebase官方提供的UI组件,一键集成手机号验证,无需手动处理reCAPTCHA和OTP输入逻辑:

import React from 'react';
import { auth } from '../firebase';
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';

const OtpVerification = () => {
  const uiConfig = {
    signInFlow: 'popup',
    signInOptions: [
      {
        provider: auth.PhoneAuthProvider.PROVIDER_ID,
        recaptchaParameters: {
          size: 'invisible'
        }
      }
    ],
    callbacks: {
      signInSuccessWithAuthResult: () => false // 阻止自动跳转,自行处理后续逻辑
    }
  };

  return (
    <StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth} />
  );
};

export default OtpVerification;

需先安装依赖:npm install react-firebaseui firebase

2. 搭配第三方OTP输入组件

如果不想用Firebase UI,可使用react-otp-input优化OTP输入体验,同时保留自定义Firebase验证逻辑:
安装依赖:npm install react-otp-input
使用示例:

import OtpInput from 'react-otp-input';

// 替换原input组件
<OtpInput
  value={otp}
  onChange={setOtp}
  numInputs={6}
  renderSeparator={<span>-</span>}
  renderInput={(props) => <input {...props} />}
/>

内容的提问来源于stack exchange,提问作者Balram Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:02:48