diff --git a/README.md b/README.md
index 7ac89db..c6b6e99 100644
--- a/README.md
+++ b/README.md
@@ -100,28 +100,6 @@ ReactDom.render(
);
```
-```javascript
-// IMPORTANT NOTES: The `GoogleReCaptcha` component is a wrapper around `useGoogleRecaptcha` hook and use `useEffect` to run the verification.
-// It's important that you understand how React hooks work to use it properly.
-// Avoid using inline function for the `onVerify` props as it can possibly cause the verify function to run continously.
-// To avoid that problem, you can use a memoized function provided by `React.useCallback` or a class method
-// The code below is an example that inline function can result in an infinite loop and the verify function runs continously:
-
-const MyComponent: FC = () => {
- const [token, setToken] = useState();
-
- return (
-
- {
- setToken(token);
- }}
- />
-
- );
-};
-```
-
```javascript
// Example of refreshReCaptcha option:
diff --git a/src/google-recaptcha.tsx b/src/google-recaptcha.tsx
index ca43eae..4185cd0 100644
--- a/src/google-recaptcha.tsx
+++ b/src/google-recaptcha.tsx
@@ -1,5 +1,6 @@
import React, { useEffect } from 'react';
import { useGoogleReCaptcha } from './use-google-recaptcha';
+import { useStableCallback } from './use-stable-callback';
import { logWarningMessage } from './utils';
export interface IGoogleRecaptchaProps {
@@ -11,10 +12,17 @@ export interface IGoogleRecaptchaProps {
export function GoogleReCaptcha({
action,
onVerify,
- refreshReCaptcha,
+ refreshReCaptcha
}: IGoogleRecaptchaProps) {
const googleRecaptchaContextValue = useGoogleReCaptcha();
+ const hasVerify = !!onVerify;
+
+ // handleVerify is a stable reference
+ // and therefore will not trip the useEffect into an infinite loop
+ // when onVerify is an anonymous or otherwise changing function.
+ const handleVerify = useStableCallback(onVerify);
+
useEffect(() => {
const { executeRecaptcha } = googleRecaptchaContextValue;
@@ -25,17 +33,23 @@ export function GoogleReCaptcha({
const handleExecuteRecaptcha = async () => {
const token = await executeRecaptcha(action);
- if (!onVerify) {
+ if (!hasVerify) {
logWarningMessage('Please define an onVerify function');
return;
}
- onVerify(token);
+ handleVerify(token);
};
handleExecuteRecaptcha();
- }, [action, onVerify, refreshReCaptcha, googleRecaptchaContextValue]);
+ }, [
+ action,
+ handleVerify,
+ hasVerify,
+ refreshReCaptcha,
+ googleRecaptchaContextValue
+ ]);
const { container } = googleRecaptchaContextValue;
diff --git a/src/use-stable-callback.ts b/src/use-stable-callback.ts
new file mode 100644
index 0000000..22f0e47
--- /dev/null
+++ b/src/use-stable-callback.ts
@@ -0,0 +1,25 @@
+import { useRef, useEffect, useState } from 'react';
+
+type AnyFunc = (...args: any[]) => any | undefined;
+
+const useStableCallback = (fn: T): T => {
+ const ref = useRef(fn);
+
+ useEffect(() => {
+ ref.current = fn;
+ }, [fn]);
+
+ const [stableFn] = useState(() => {
+ const newFn = (...args: any[]) => {
+ if (ref.current) {
+ return ref.current(...args);
+ }
+ };
+
+ return newFn as T;
+ });
+
+ return stableFn;
+};
+
+export { useStableCallback };