Skip to content

Commit df84dea

Browse files
committed
added inline badge render
1 parent 4ccbb50 commit df84dea

File tree

3 files changed

+66
-17
lines changed

3 files changed

+66
-17
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ There are three ways to trigger the recaptcha validation: using the `GoogleReCap
8282

8383
#### GoogleReCaptcha
8484

85-
`GoogleRecaptcha` is a react component that can be used in your app to trigger the validation. It provides a prop `onVerify`, which will be called once the verify is done successfully.
85+
`GoogleRecaptcha` is a react component that can be used in your app to trigger the validation. It provides a prop `onVerify`, which will be called once the verify is done successfully, also supports a prop `refreshReCaptcha` which supports any type of value and is used to force recaptcha to revalidate (you can use a timestamp updated after every submit), there is an example below.
8686

8787
```javascript
8888
import {
@@ -120,6 +120,36 @@ const MyComponent: FC = () => {
120120
};
121121
```
122122

123+
```javascript
124+
// Example of refreshReCaptcha option:
125+
126+
const MyComponent: FC = () => {
127+
const [token, setToken] = useState();
128+
const [refreshReCaptcha, setRefreshReCaptcha] = useState(false);
129+
130+
const onVerify = useCallback((token) => {
131+
setToken(token);
132+
});
133+
134+
const doSomething = () => {
135+
/* do something like submit a form and then refresh recaptcha */
136+
setRefreshReCaptcha(r => !r);
137+
}
138+
139+
return (
140+
<div>
141+
<GoogleReCaptcha
142+
onVerify={onVerify}
143+
refreshReCaptcha={refreshReCaptcha}
144+
/>
145+
<button onClick={doSomething}>
146+
Do Something
147+
</button>
148+
</div>
149+
);
150+
};
151+
```
152+
123153
#### React Hook: useGoogleReCaptcha (recommended approach)
124154

125155
If you prefer a React Hook approach over the old good Higher Order Component, you can choose to use the custom hook `useGoogleReCaptcha` over the HOC `withGoogleReCaptcha`.

src/google-recaptcha-provider.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import React from 'react';
2-
import {
1+
import React, {
32
useRef,
43
useMemo,
54
useState,
@@ -47,6 +46,7 @@ interface IGoogleReCaptchaProviderProps {
4746

4847
export interface IGoogleReCaptchaConsumerProps {
4948
executeRecaptcha?: (action?: string) => Promise<string>;
49+
inlineBadgeId?: string | HTMLElement;
5050
}
5151

5252
const GoogleReCaptchaContext = createContext<IGoogleReCaptchaConsumerProps>({
@@ -67,15 +67,15 @@ export function GoogleReCaptchaProvider({
6767
scriptProps,
6868
language,
6969
inlineBadgeId,
70-
parameters = {},
70+
parameters,
7171
children
7272
}: IGoogleReCaptchaProviderProps) {
7373
const [greCaptchaInstance, setGreCaptchaInstance] = useState<null | {
7474
execute: Function;
7575
}>(null);
7676
const clientId = useRef<number | string>(reCaptchaKey);
77-
78-
const scriptPropsJson = JSON.stringify(scriptProps);
77+
const { current: scriptPropsRef } = useRef<any>(scriptProps);
78+
const { current: parametersRef } = useRef<any>(parameters);
7979

8080
useEffect(() => {
8181
if (!reCaptchaKey) {
@@ -86,8 +86,8 @@ export function GoogleReCaptchaProvider({
8686
return;
8787
}
8888

89-
const scriptId = scriptProps?.id || 'google-recaptcha-v3';
90-
const onLoadCallbackName = scriptProps?.onLoadCallbackName || 'onRecaptchaLoadCallback';
89+
const scriptId = scriptPropsRef?.id || 'google-recaptcha-v3';
90+
const onLoadCallbackName = scriptPropsRef?.onLoadCallbackName || 'onRecaptchaLoadCallback';
9191

9292
((window as unknown) as {[key: string]: () => void})[onLoadCallbackName] = () => {
9393
/* eslint-disable @typescript-eslint/no-explicit-any */
@@ -99,7 +99,7 @@ export function GoogleReCaptchaProvider({
9999
badge: 'inline',
100100
size: 'invisible',
101101
sitekey: reCaptchaKey,
102-
...(parameters || {})
102+
...(parametersRef || {})
103103
};
104104
clientId.current = grecaptcha.render(inlineBadgeId, params);
105105
};
@@ -131,7 +131,7 @@ export function GoogleReCaptchaProvider({
131131
onLoadCallbackName,
132132
useEnterprise,
133133
useRecaptchaNet,
134-
scriptProps,
134+
scriptProps: scriptPropsRef,
135135
language,
136136
onLoad,
137137
onError
@@ -140,17 +140,24 @@ export function GoogleReCaptchaProvider({
140140
return () => {
141141
cleanGoogleRecaptcha(scriptId);
142142
};
143-
}, [useEnterprise, useRecaptchaNet, scriptPropsJson, language, reCaptchaKey]);
143+
}, [
144+
useEnterprise,
145+
useRecaptchaNet,
146+
scriptPropsRef,
147+
parametersRef,
148+
language,
149+
reCaptchaKey
150+
]);
144151

145152
const executeRecaptcha = useCallback(
146-
async (action?: string) => {
153+
(action?: string) => {
147154
if (!greCaptchaInstance || !greCaptchaInstance.execute) {
148155
throw new Error(
149156
'<GoogleReCaptchaProvider /> Google Recaptcha has not been loaded'
150157
);
151158
}
152159

153-
return await greCaptchaInstance.execute(clientId.current, { action });
160+
return greCaptchaInstance.execute(clientId.current, { action });
154161
},
155162
[greCaptchaInstance, clientId]
156163
);

src/google-recaptcha.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
import { useEffect } from 'react';
1+
import React, { useEffect } from 'react';
22
import { useGoogleReCaptcha } from './use-google-recaptcha';
33
import { logWarningMessage } from './utils';
44

55
export interface IGoogleRecaptchaProps {
66
onVerify: (token: string) => void | Promise<void>;
77
action?: string;
8+
refreshReCaptcha?: any,
89
}
910

10-
export function GoogleReCaptcha({ action, onVerify }: IGoogleRecaptchaProps) {
11+
export function GoogleReCaptcha({
12+
action,
13+
onVerify,
14+
refreshReCaptcha,
15+
}: IGoogleRecaptchaProps) {
1116
const googleRecaptchaContextValue = useGoogleReCaptcha();
1217

1318
useEffect(() => {
1419
const { executeRecaptcha } = googleRecaptchaContextValue;
1520

1621
if (!executeRecaptcha) {
17-
return;
22+
// return value is not used, but here is used to avoid unused dependencies
23+
return refreshReCaptcha;
1824
}
1925

2026
const handleExecuteRecaptcha = async () => {
@@ -30,7 +36,13 @@ export function GoogleReCaptcha({ action, onVerify }: IGoogleRecaptchaProps) {
3036
};
3137

3238
handleExecuteRecaptcha();
33-
}, [action, onVerify, googleRecaptchaContextValue]);
39+
}, [action, onVerify, refreshReCaptcha, googleRecaptchaContextValue]);
40+
41+
const { inlineBadgeId } = googleRecaptchaContextValue;
42+
43+
if (typeof inlineBadgeId === 'string') {
44+
return <div id={inlineBadgeId} />;
45+
}
3446

3547
return null;
3648
}

0 commit comments

Comments
 (0)