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

如何在最新react-hook-form中正确集成react-hook-recaptcha?

解决 react-hook-recaptcha 与最新 react-hook-form 集成问题

关键修复点:

  1. 补全缺失类型:定义Newsletter接口,解决类型报错
  2. 正确初始化reCAPTCHA:使用useRecaptcha钩子加载并管理验证码实例
  3. 移除冗余状态:删除contact状态,直接用react-hook-form的表单状态管理
  4. 整合验证逻辑:提交表单前先执行reCAPTCHA验证,通过后再处理业务逻辑

修改后的完整代码:

"use client"

import { useCallback, useEffect, useState } from "react"
import { useForm, SubmitHandler, FormEvent } from "react-hook-form"
import { useRecaptcha } from "react-hook-recaptcha"
import { cn } from "@/lib/utils"
import { z, ZodType } from "zod"
import Alert from "./Alert"
import Button from "./Button"
import { zodResolver } from "@hookform/resolvers/zod"

// 补全缺失的类型定义
interface Newsletter {
  email: string
}

const Newsletter = () => {
  const [isSubmitted, setIsSubmitted] = useState<boolean>(false)
  const [recaptchaError, setRecaptchaError] = useState<string>("")

  const sitekey = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI" // 替换为你的实际站点密钥
  const containerId = "test-recaptcha"

  const schema: ZodType<Newsletter> = z.object({
    email: z.string().email({ message: "Ongeldig e-mailadres" })
  })

  const {
    register,
    handleSubmit,
    reset,
    clearErrors,
    formState: { errors, isSubmitSuccessful }
  } = useForm<Newsletter>({
    resolver: zodResolver(schema),
    reValidateMode: "onSubmit"
  })

  // 初始化reCAPTCHA
  const { execute, resetRecaptcha, token } = useRecaptcha({
    sitekey,
    containerId,
    // 可选:配置验证码主题、大小等
    // theme: "dark",
    // size: "compact"
  })

  // 移除冗余的contact状态,直接用react-hook-form管理
  const handleInputChange = (e: FormEvent<HTMLInputElement>) => {
    clearErrors("email")
    setRecaptchaError("")
  }

  const onSubmit: SubmitHandler<Newsletter> = useCallback(async (data) => {
    try {
      // 执行reCAPTCHA验证
      const recaptchaToken = await execute()
      if (!recaptchaToken) {
        setRecaptchaError("Voer de reCAPTCHA-verificatie in")
        return
      }

      // 这里添加你的实际提交逻辑,比如调用API,带上recaptchaToken
      console.log("表单数据:", data)
      console.log("reCAPTCHA Token:", recaptchaToken)

      setIsSubmitted(true)
      reset()
      resetRecaptcha() // 重置验证码
    } catch (error) {
      setRecaptchaError("reCAPTCHA-verificatie mislukt, probeer opnieuw")
    }
  }, [execute, reset, resetRecaptcha])

  const onFormValidate = useCallback(() => {
    if (errors.email || recaptchaError) {
      setIsSubmitted(false)
    }

    if (isSubmitSuccessful) {
      setIsSubmitted(true)
    }
  }, [errors, isSubmitSuccessful, recaptchaError])

  useEffect(() => {
    onFormValidate()
  }, [onFormValidate])

  const email = register("email")

  return (
    <div className="text-midnight bg-accent sm:rounded-2xl">
      <div className="flex flex-col flex-wrap content-center justify-center pt-6 pb-12 mx-auto md:py-12">
        <h2 className="text-3xl leading-none text-center sm:text-5xl lg:text-6xl font-playfair">
          Stay in the loop!
        </h2>

        <p className="max-w-lg pt-4 pb-8 mx-auto text-center text-md">
          Houd ons in de gaten, misschien staan we binnenkort bij jou in de
          buurt of op een festival!
        </p>

        <form
          autoComplete="off"
          className="space-y-3"
          onSubmit={handleSubmit(onSubmit)}
        >
          <div className="flex flex-col sm:flex-row">
            <input
              {...email}
              onChange={handleInputChange}
              className={cn(
                errors.email
                  ? "placeholder:text-red-800 border-red-800"
                  : "placeholder:text-midnight border-midnight",
                "flex-grow p-3 bg-white border-1 text-sm md:text-base outline-none rounded-tl-lg rounded-tr-lg sm:rounded-tr-none sm:rounded-br-none sm:rounded-l-lg text-midnight placeholder:text-midnight focus:outline-none"
              )}
              placeholder="e-mailadres..."
            />

            <Button
              buttonType="submit"
              text="Versturen"
              buttonClass="btn-secondary border-2 rounded-tl-none rounded-tr-none sm:rounded-tr-lg sm:rounded-bl-none px-7 rounded-lg"
            />
          </div>

          {errors.email && (
            <p className="text-xs font-bold text-red-800">
              {errors.email.message}
            </p>
          )}

          {recaptchaError && (
            <p className="text-xs font-bold text-red-800">
              {recaptchaError}
            </p>
          )}

          {isSubmitted && (
            <Alert
              type="success"
              message={`Bedankt voor het aanmelden van ons nieuwsbrief`}
            />
          )}

          <div id={containerId} className="mt-4" />
        </form>
      </div>
    </div>
  )
}

export default Newsletter

核心说明:

  • useRecaptcha 初始化:传入站点密钥和容器ID后,钩子会自动加载reCAPTCHA脚本并渲染验证码组件
  • 提交验证:在onSubmit中先调用execute()触发验证码验证,拿到有效token后再执行后续提交逻辑
  • 状态清理:提交成功后调用resetRecaptcha()重置验证码,方便用户再次提交
  • 冗余状态移除:react-hook-form已经提供了完整的表单状态管理,不需要额外维护contact状态,避免状态不一致问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:47:02