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

Next.js中Firebase OTP验证出现RecaptchaVerifier销毁错误的原因与解决

解决'RecaptchaVerifier instance has been destroyed'错误

你遇到的问题根源在于handleSubmit里调用了window.recaptchaVerifier.clear()——这个方法会彻底销毁RecaptchaVerifier实例,而非仅重置验证状态。当不刷新页面重新进入表单时,window.recaptchaVerifier变量虽仍存在,但指向的实例已被销毁,后续调用render()或reset()自然触发报错。

方案1:替换clear()为reset(),保留实例可用性

将handleSubmit中的clear()改为reset(),后者仅重置验证码状态,不会销毁实例,确保下次使用时实例仍有效。

修改后的handleSubmit代码:

const handleSubmit = async (otp: any) => {
    try {
      setLoading(true);
      if (otp) {
        const confirmOtp = await otpInfo.confirmResult.confirm(otp);
        if (confirmOtp) {
          toast.success('Phone number verified successfully!');
          setOtpInfo((prev: any) => ({ ...prev, otpVerified: true }));
          // 用reset替代clear,不销毁实例
          window.recaptchaVerifier.reset();
          closeModalHandler();
        }
      } else {
        toast.error('Invalid OTP');
      }
    } catch (error) {
      toast.error('Invalid OTP please try again');
    } finally {
      setLoading(false);
    }
  };

方案2:增加实例有效性检查,失效时重新创建

若需在特定场景销毁实例(如用户切换表单类型),可在verifyPhoneNumber中先检查实例可用性,失效则重新创建:

修改后的verifyPhoneNumber代码:

const verifyPhoneNumber = async () => {
    setVerifyNumberLoader(true);
    if (otpInfo.otpVerified) return;
    try {
      // 检查实例是否存在且未被销毁
      if (!window.recaptchaVerifier || window.recaptchaVerifier['grecaptcha'] === null) {
        // 清理旧实例(如果存在)
        if (window.recaptchaVerifier) {
          window.recaptchaVerifier.clear();
        }
        // 创建新实例
        window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
          "recaptcha-container",
          {
            size: "invisible",
          },
        );
      }
      await window.recaptchaVerifier.render();
      const appVerifier = window.recaptchaVerifier;
      const result = await firebase
        .auth()
        .signInWithPhoneNumber('+' + state.phone, appVerifier);
      if (result) {
        setTimeLeft(60);
        setIsDisabled(false)
        toast.success('OTP sent to your phone number');
        openModalHandler();
        setOtpInfo((prev: any) => ({ ...prev, confirmResult: result }));
      }
    } catch (error) {
      console.log(error)
      toast.error(error.message);
      setVerifyNumberLoader(false);
    } finally {
      if (window.recaptchaVerifier) {
        window.recaptchaVerifier.reset();
      }
      setVerifyNumberLoader(false);
    }
  };

额外优化:组件卸载时清理实例

若注册表单是独立组件,在组件卸载时清理实例避免内存泄漏:

useEffect(() => {
  return () => {
    if (window.recaptchaVerifier) {
      window.recaptchaVerifier.clear();
      delete window.recaptchaVerifier;
    }
  };
}, []);

以上修改后,无论首次发送OTP还是用户完成注册后不刷新页面重新操作,都不会再出现实例已销毁的错误。你之前用reset()解决"recaptcha client element has been removed"的思路正确,核心就是避免轻易销毁RecaptchaVerifier实例,优先通过重置状态复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:25:11