Sumit
Sumit

Reputation: 50

How to resolve the error reCAPTCHA has already been rendered when using reCaptcha v2 as fallback of v3

We are trying to use the combination of reCaptcha v2 and v3 in the login page so we explicit render the reCaptcha v2 widget(challenge based reCaptcha) if reCaptcha v3 (invisible reCaptcha) fails.

Here's the rough flow -

  1. User enter creds and hit the Sign-in button,
  2. FE Send BE auth request along with v3 token,
  3. If BE respond with v3 failure then FE explicit render reCaptcha v2,
  4. User solve the reCaptcha challenge and FE again make BE auth call along with v2 token,
  5. Let's say BE unable to verify the v2 token,
  6. We display some error to the user but user again click on login button,
  7. We send BE auth request to server and let's say v3 failed again,
  8. this time when we try to render the v2 widget again then we are encountering this Error -
    reCAPTCHA has already been rendered in this element

What I've tried -

I tried using the reset method when BE fails to verify the v2 token -

grecaptcha.reset();

but the reset method only uncheck the reCaptcha and doesn't de-render or destroy the reCaptcha.

I also tried programmatically removing the children of recaptcha container using .removeChild() method in JavaScript but encountering the same error.

Please help me resolve this error?

Upvotes: 0

Views: 279

Answers (1)

Pranay Kumar Kyasala
Pranay Kumar Kyasala

Reputation: 367

The error reCAPTCHA has already been rendered in this element, that you are encountering is because you are loading reCAPTCHA twice at the same element.

As per this Github issue :

The problem is that the DOM generated by this.props.grecaptcha.render() is not removed during <ReCAPTCHA's unmount and therefore can cause trouble when rendering a new instance at the same place.

I can see two possible solutions :

  1. Implement componentWillUnmount to do following :

    • Remove all DOM generated by this.props.grecaptcha.render() including the render target element. (we don't want to remove the div generated by React, so we probably want to manually add a wrapper div for this purpose)

    • Call grecaptcha.reset(widgetId) to do memory cleaning (as mentioned here and here)

  2. Detach rendered DOM inside componentWillUnmount and save it into some global variable for later reuse. This prevents the component from slow reloading after each use, however different instances may need different rendering parameters so this has to be taken into account.

Refer to this Stack link and also check this Github issue for more information which might be helpful for you.

Upvotes: 1

Related Questions