Reputation: 7493
I have been using react-hook-form before, for users to submit their email address in a basic form:
BEFORE: react-hook-form, no catpcha
import React from 'react'
import { useForm } from 'react-hook-form'
import { useRouter } from 'next/router'
const MyForm = ({ btnText = 'Join' }) => {
const router = useRouter()
const {
register,
handleSubmit,
formState: { isSubmitted, isSubmitting, isValid, errors },
reset,
} = useForm({
mode: 'onChange',
reValidateMode: 'onChange',
})
const onSubmit = async ({ email }) => {
const response = await fetch('/api/my-endpoint', {
method: 'POST',
body: JSON.stringify({
email: email,
captcha: captchaCode,
}),
headers: {
'Content-Type': 'application/json',
},
})
}
return (
<div tw="">
<form
onSubmit={handleSubmit(onSubmit)}
>
<input
{...register('email', {
required: 'We need an e-mail address',
})}
type="email"
/>
<button
type="submit"
>
Submit
</button>
</form>
</div>
)
}
export default MyForm
Now I just added google ReCaptcha v2, but I struggle to understand how to integrate it into react-hoook-form?
NOW: react-hook-form + google recatpcha v2
import React from 'react'
import { useForm } from 'react-hook-form'
import ReCAPTCHA from 'react-google-recaptcha'
const MyForm = ({ btnText = 'Join' }) => {
const {
register,
handleSubmit,
formState: { isSubmitted, isSubmitting, isValid, errors },
reset,
} = useForm({
mode: 'onChange',
reValidateMode: 'onChange',
})
const onSubmit = ({ email }) => {
// Execute the reCAPTCHA when the form is submitted
recaptchaRef.current.execute()
}
const onReCAPTCHAChange = async captchaCode => {
// If the reCAPTCHA code is null or undefined indicating that
// the reCAPTCHA was expired then return early
if (!captchaCode) {
return
}
try {
const response = await fetch('/api/my-endpoint', {
method: 'POST',
body: JSON.stringify({
email: email,
captcha: captchaCode,
}),
headers: {
'Content-Type': 'application/json',
},
})
if (response.ok) {
// If the response is ok than show the success alert
alert('Email registered successfully')
} else {
// Else throw an error with the message returned
// from the API
const error = await response.json()
throw new Error(error.message)
}
} catch (error) {
alert(error?.message || 'Something went wrong')
} finally {
// Reset the reCAPTCHA when the request has failed or succeeeded
// so that it can be executed again if user submits another email.
recaptchaRef.current.reset()
reset()
}
}
return (
<form
onSubmit={handleSubmit(onSubmit)}
>
<ReCAPTCHA
ref={recaptchaRef}
size="invisible"
sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}
onChange={onReCAPTCHAChange}
/>
<input
{...register('email', {
required: 'We need an e-mail address',
})}
type="email"
/>
<button
type="submit"
>
Submit
</button>
</form>
)
}
export default MyForm
My Problem:
What I seem to struggle with, is that before I used to do an async handleSubmit call:
const onSubmit = async ({ email }) => {
const response = await fetch('/api/my-endpoint', {
method: 'POST',
body: JSON.stringify({
email: email,
captcha: captchaCode,
}),
headers: {
'Content-Type': 'application/json',
},
})
}
Whereas now, onSubmit
just activates the captcha:
const onSubmit = ({ email }) => {
// Execute the reCAPTCHA when the form is submitted
recaptchaRef.current.execute()
}
...and my actual request is now only being submitted inside the onReCAPTCHAChange
function. There, I don't have access to react-hook-form value of email anymore. How can I get that access there?
Also: my handleSubmit
function is now synchronous, so I cannot wait for the API response? How can I make this async, but still work with react-hook-form
and recaptcha
? Any advice?
Upvotes: 4
Views: 6142
Reputation: 861
You can call your real onSubmit
function with the data you need by calling the function returned by handleSubmit
:
// inside your reCAPTCHA response function
const onSubmitWithFormValues = handleSubmit(
// binding form values to your function and any other params (e.g. token)
(...formSubmitParams) => onSubmit(...formSubmitParams, recaptchaToken)
)
onSubmitWithFormValues()
For the above example, the onSubmit
signature is the following:
const onSubmit = ({ email, password, username }, _ /* unused event */, recaptchaToken: string) => { ... }
Upvotes: 1
Reputation: 84
useForm
provides a getValues()
function to get the values of form. You can use it any where inside you component.
Here's the reference: https://react-hook-form.com/api/useform/getvalues
const { getValues } = useForm()
const onReCAPTCHAChange = async captchaCode => {
// If the reCAPTCHA code is null or undefined indicating that
// the reCAPTCHA was expired then return early
if (!captchaCode) {
return
}
try {
const values = getValues()
const response = await fetch('/api/my-endpoint', {
method: 'POST',
body: JSON.stringify({
email: values.email,
captcha: captchaCode,
}),
headers: {
'Content-Type': 'application/json',
},
})
}
....
}
Alternatively, you can use executeAsync
instead of execute
inside your onSubmit
of hook form and then execute your request.
const onSubmit = ({ email }) => {
const token = await recaptchaRef.current.executeAsync();
// You API call here
}
Upvotes: 2