firebase / firebase/firebase-js-sdk
grecaptcha keeps a reference to my div in window.___grecaptcha_cfg.clients even after RecaptchaVerifier.clear()
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 37
Description
### Operating System
macOS 14.2 (23C64)
### Browser Version
Chrome 121.0.6167.160 (Official Build) (arm64)
### Firebase SDK Version
10.8.0
### Firebase SDK Product:
Auth
### Describe your project's tooling
Next.js 14
### Describe the problem
When reloading my components (because some state changed or a code change triggered hot reload) I clear the RedirectVerifier and the innerHtml of the container div. Then when I create a new RecaptchaVerifier, pass the same div as container and try to render it I get an `Error: reCAPTCHA has already been rendered in this element`.
Using the chrome devtools I found out that grecaptcha has a reference to my div in `window.___grecaptcha_cfg.clients` even after I use RecaptchaVerifier.clear(). So when I try to render the new RecaptchaVerifier using the same div it breaks even if it is empty and the previos ReaptchaVerifier no longer exists.
I can work around this by manually clearing that reference between rerenders or by using a new div so it's not the same reference but I think RecaptchaVerifier.clear() should take care of this.
### Steps and code to reproduce issue
### Steps
1. Have an empty div
2. Create a RecaptchaVerifier using the div created in step 1 as container
3. Render the RecaptchaVerifier (RecaptchaVerifier.render())
4. Clear the RecaptchaVerifier (RecaptchaVerifier.render())
5. Clear the container div (containerRef.innerHtml = '')
6. Repeat steps 2 to 4
### My Code
**Recaptcha container**
```typescript
export type RecaptchaProps = {
containerRef: React.Ref;
};
export const Recaptcha = ({ containerRef }: RecaptchaProps) => {
return
};
```
**RecaptchaVerifier**
```typescript
import { getAuth, RecaptchaVerifier } from 'firebase/auth';
import { useCallback, useEffect, useState } from 'react';
export const useRecaptcha = () => {
const [containerRef, setContainerRef] = useState(null);
const [verifier, setVerifier] = useState();
const createVerifier = useCallback((containerRef: HTMLDivElement | null) => {
let verifier: RecaptchaVerifier | undefined;
if (containerRef !== null) {
console.log(containerRef);
verifier = new RecaptchaVerifier(getAuth(), containerRef, {
size: 'invisible',
});
}
return verifier;
}, []);
const clear = useCallback(
(
verifier: RecaptchaVerifier | undefined,
containerRef: HTMLDivElement | null,
) => {
verifier?.clear();
if (containerRef !== null) {
containerRef.innerHTML = '';
}
},
[],
);
useEffect(() => {
const newVerifier = createVerifier(containerRef);
newVerifier?.render().then(
() => {
setVerifier(newVerifier);
},
(error) => console.log(error),
);
return () => clear(newVerifier, containerRef);
}, [createVerifier, containerRef, setVerifier, clear]);
return { verifier, containerRef: setContainerRef };
};
```
**Login Page**
```typescript
const LoginPage = () => {
const { verifier, containerRef } = useRecaptcha()
[...]
return (
[...]
);
}
```
Contributor guide
Assessment
This issue has not been assessed yet.